From c89efd251cd218c34297226301608e13954f2931 Mon Sep 17 00:00:00 2001
From: uramer <antonuramer@gmail.com>
Date: Sun, 7 Apr 2019 01:27:15 +0200
Subject: [PATCH] [General] Implement CellReset packet, stage 2

---
 .../openmw-mp/Script/Functions/Worldstate.cpp |  24 ++++-
 .../openmw-mp/Script/Functions/Worldstate.hpp |   2 +-
 apps/openmw/mwbase/world.hpp                  |  12 ++-
 apps/openmw/mwmp/CellController.cpp           |   8 +-
 .../worldstate/ProcessorCellReset.hpp         |  20 ++--
 apps/openmw/mwworld/cellstore.cpp             |  55 +++++++++-
 apps/openmw/mwworld/cellstore.hpp             |  20 ++++
 apps/openmw/mwworld/worldimp.cpp              | 101 +++++++++++++++++-
 apps/openmw/mwworld/worldimp.hpp              |  12 ++-
 9 files changed, 231 insertions(+), 23 deletions(-)

diff --git a/apps/openmw-mp/Script/Functions/Worldstate.cpp b/apps/openmw-mp/Script/Functions/Worldstate.cpp
index 1186ad4be..d963cbf4c 100644
--- a/apps/openmw-mp/Script/Functions/Worldstate.cpp
+++ b/apps/openmw-mp/Script/Functions/Worldstate.cpp
@@ -3,6 +3,7 @@
 #include <apps/openmw-mp/Networking.hpp>
 #include <apps/openmw-mp/Player.hpp>
 #include <apps/openmw-mp/Script/ScriptFunctions.hpp>
+#include <apps/openmw-mp/CellController.hpp>
 #include <fstream>
 
 #include <apps/openmw-mp/Utils.hpp>
@@ -299,8 +300,29 @@ void WorldstateFunctions::SendCellReset(unsigned short pid, bool sendToOtherPlay
     writeWorldstate.guid = player->guid;
 
     packet->setWorldstate(&writeWorldstate);
-    
+
     packet->Send(sendToOtherPlayers);
+
+    if (sendToOtherPlayers)
+    {
+        packet->Send(false);
+    }
+
+    CellController * cellController = CellController::get();
+
+    for (ESM::Cell cell : writeWorldstate.cellsToReset)
+    {
+        if (sendToOtherPlayers)
+        {
+            TPlayers * players = Players::getPlayers();
+            for (TPlayers::iterator iter = players->begin(); iter != players->end(); iter++)
+            {
+                cellController->getCell(&cell)->removePlayer((*iter).second, true);
+            }
+        }
+        else
+            cellController->getCell(&cell)->removePlayer(Players::getPlayer(pid), true);
+    }
 }
 
 
diff --git a/apps/openmw-mp/Script/Functions/Worldstate.hpp b/apps/openmw-mp/Script/Functions/Worldstate.hpp
index 23eb31dc5..1fe13bb94 100644
--- a/apps/openmw-mp/Script/Functions/Worldstate.hpp
+++ b/apps/openmw-mp/Script/Functions/Worldstate.hpp
@@ -57,7 +57,7 @@
     \
     {"AddCellToReset",                    WorldstateFunctions::AddCellToReset},\
     {"ClearCellsToReset",                 WorldstateFunctions::ClearCellsToReset},\
-    {"SendCellsToReset",                  WorldstateFunctions::SendCellReset},\
+    {"SendCellReset",                  WorldstateFunctions::SendCellReset},\
     \
     {"ReadLastWorldstate",                WorldstateFunctions::ReadLastWorldstate},\
     {"CopyLastWorldstateToStore",         WorldstateFunctions::CopyLastWorldstateToStore}
diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp
index 43b1d1af6..547ff2220 100644
--- a/apps/openmw/mwbase/world.hpp
+++ b/apps/openmw/mwbase/world.hpp
@@ -579,7 +579,17 @@ namespace MWBase
 
                 Make it possible to check whether a cell is active
             */
-            virtual bool isCellActive(MWWorld::CellStore* cell) = 0;
+            virtual bool isCellActive(ESM::Cell cell) = 0;
+            /*
+                End of tes3mp addition
+            */
+
+            /*
+                Start of tes3mp addition
+
+                Make it possible to reload active cells (e.g. for CellReset)
+            */
+            virtual void reloadCells(std::vector<ESM::Cell> * cells) = 0;
             /*
                 End of tes3mp addition
             */
diff --git a/apps/openmw/mwmp/CellController.cpp b/apps/openmw/mwmp/CellController.cpp
index e2d07b084..64b96904d 100644
--- a/apps/openmw/mwmp/CellController.cpp
+++ b/apps/openmw/mwmp/CellController.cpp
@@ -35,7 +35,7 @@ void CellController::updateLocal(bool forceUpdate)
     {
         mwmp::Cell *mpCell = it->second;
 
-        if (!MWBase::Environment::get().getWorld()->isCellActive(mpCell->getCellStore()))
+        if (!MWBase::Environment::get().getWorld()->isCellActive(*(mpCell->getCellStore()->getCell())))
         {
             mpCell->uninitializeLocalActors();
             mpCell->uninitializeDedicatedActors();
@@ -312,11 +312,7 @@ bool CellController::isInitializedCell(const ESM::Cell& cell)
 
 bool CellController::isActiveWorldCell(const ESM::Cell& cell)
 {
-    MWWorld::CellStore *cellStore = getCellStore(cell);
-
-    if (!cellStore) return false;
-
-    return MWBase::Environment::get().getWorld()->isCellActive(cellStore);
+    return MWBase::Environment::get().getWorld()->isCellActive(cell);
 }
 
 Cell *CellController::getCell(const ESM::Cell& cell)
diff --git a/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp b/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp
index 1a24cb0e0..941ed6b30 100644
--- a/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp
+++ b/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp
@@ -2,6 +2,7 @@
 #define OPENMW_PROCESSORCELLRESET_HPP
 
 #include "../WorldstateProcessor.hpp"
+#include <apps/openmw/mwworld/player.hpp>
 
 namespace mwmp
 {
@@ -16,19 +17,20 @@ namespace mwmp
         virtual void Do(WorldstatePacket &packet, Worldstate &worldstate)
         {
             LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_CELL_RESET");
+
             CellController* cellController = Main::get().getCellController();
+            MWBase::World * world = MWBase::Environment::get().getWorld();
+
+            world->reloadCells(&worldstate.cellsToReset);
+
+
             
-            for (ESM::Cell cell : worldstate.cellsToReset)
+            /*for (ESM::Cell cell : worldstate.cellsToReset)
             {
-                MWWorld::CellStore * cellStore = cellController->getCellStore(cell);
-                if (cellStore != nullptr)
-                {
-                    LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Resetting cell %s!", cell.getDescription().c_str());
-                    cellStore->clear();
-                }
-                else
-                    LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Attempted to reset an uninitialized cell %s!", cell.getDescription().c_str());
+                Main::get().getLocalPlayer()->storeCellState(cell, CellState::LOAD);
             }
+            Main::get().getLocalPlayer()->sendCellStates();
+            Main::get().getLocalPlayer()->clearCellStates();*/
         }
     };
 }
diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp
index 5327a0898..76e1f9f85 100644
--- a/apps/openmw/mwworld/cellstore.cpp
+++ b/apps/openmw/mwworld/cellstore.cpp
@@ -605,6 +605,41 @@ namespace MWWorld
         End of tes3mp addition
     */
 
+    /*
+        Start of tes3mp addition
+
+        Make it possible to get mMovedHere in the CellStore from elsewhere in the code
+    */
+    std::vector<Ptr> CellStore::getMovedHere()
+    {
+        std::vector<Ptr> hereVector;
+        for (CellStore::MovedRefTracker::iterator iter = mMovedHere.begin(); iter != mMovedHere.end(); ++iter)
+        {
+            hereVector.push_back(Ptr(iter->first, iter->second));
+        }
+        return hereVector;
+    }
+    /*
+        End of tes3mp addition
+    */
+
+    /*
+        Start of tes3mp addition
+
+        Make it possible to return all NPCs back to this cell from elsewhere in the code
+    */
+    void CellStore::returnFromOtherCells()
+    {
+        for (CellStore::MovedRefTracker::iterator iter = mMovedToAnotherCell.begin(); iter != mMovedToAnotherCell.end(); ++iter)
+        {
+            LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Returning actor from %d, %d!", iter->second->getCell()->getGridX(), iter->second->getCell()->getGridY());
+            iter->second->moveTo(iter->first, this);
+        }
+    }
+    /*
+        End of tes3mp addition
+    */
+
     float CellStore::getWaterLevel() const
     {
         if (isExterior())
@@ -1198,7 +1233,6 @@ namespace MWWorld
             mBooks.mList.clear();
             mClothes.mList.clear();
             mContainers.mList.clear();
-            mCreatures.mList.clear();
             mDoors.mList.clear();
             mIngreds.mList.clear();
             mCreatureLists.mList.clear();
@@ -1206,13 +1240,30 @@ namespace MWWorld
             mLights.mList.clear();
             mLockpicks.mList.clear();
             mMiscItems.mList.clear();
-            mNpcs.mList.clear();
             mProbes.mList.clear();
             mRepairs.mList.clear();
             mStatics.mList.clear();
             mWeapons.mList.clear();
             mBodyParts.mList.clear();
 
+            mwmp::CellController * cellController = mwmp::Main::get().getCellController();
+
+            for (std::list<LiveCellRef<ESM::Creature>>::iterator ref = mCreatures.mList.begin(); ref != mCreatures.mList.end(); ref++)
+            {
+                if (!cellController->isDedicatedActor(MWWorld::Ptr(&*ref, this)))
+                {
+                    mCreatures.mList.erase(ref);
+                }
+            }
+
+            for (std::list<LiveCellRef<ESM::NPC>>::iterator ref = mNpcs.mList.begin(); ref != mNpcs.mList.end(); ref++)
+            {
+                if (!cellController->isDedicatedActor(MWWorld::Ptr(&*ref, this)))
+                {
+                    mNpcs.mList.erase(ref);
+                }
+            }
+
             mMovedHere.clear();
             mMovedToAnotherCell.clear();
             mMergedRefs.clear();
diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp
index 3975c698d..6e7d9d585 100644
--- a/apps/openmw/mwworld/cellstore.hpp
+++ b/apps/openmw/mwworld/cellstore.hpp
@@ -289,6 +289,26 @@ namespace MWWorld
                 End of tes3mp addition
             */
 
+            /*
+                Start of tes3mp addition
+
+                Make it possible to get the mContainers in the CellStore from elsewhere in the code
+            */
+            std::vector<Ptr> getMovedHere();
+            /*
+                End of tes3mp addition
+            */
+
+            /*
+                Start of tes3mp addition
+
+                Make it possible to get mMovedHere in the CellStore from elsewhere in the code
+            */
+            void returnFromOtherCells();
+            /*
+                End of tes3mp addition
+            */
+
             float getWaterLevel() const;
 
             void setWaterLevel (float level);
diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp
index c4ad67d53..286689991 100644
--- a/apps/openmw/mwworld/worldimp.cpp
+++ b/apps/openmw/mwworld/worldimp.cpp
@@ -2691,9 +2691,106 @@ namespace MWWorld
 
         Make it possible to check whether a cell is active
     */
-    bool World::isCellActive(MWWorld::CellStore* cell)
+    bool World::isCellActive(ESM::Cell cell)
     {
-        return mWorldScene->isCellActive(*cell);
+        MWWorld::Scene::CellStoreCollection activeCells = (*mWorldScene).getActiveCells();
+        mwmp::CellController* cellController = mwmp::Main::get().getCellController();
+        for (MWWorld::Scene::CellStoreCollection::iterator iter = activeCells.begin(); iter != activeCells.end(); iter++)
+        {
+            ESM::Cell iterCell = *(*iter)->getCell();
+            if (cellController->isSameCell(iterCell, cell)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+    /*
+        End of tes3mp addition
+    */
+
+    /*
+    */
+
+    /*
+        Start of tes3mp addition
+
+        Make it possible to reload active cells (e.g. for CellReset)
+    */
+    void World::reloadCells(std::vector<ESM::Cell> * cells)
+    {
+        mwmp::CellController* cellController = mwmp::Main::get().getCellController();
+        MWWorld::Scene::CellStoreCollection activeCells = (*mWorldScene).getActiveCells();
+
+        MWWorld::Scene::CellStoreCollection activeToReset;
+
+        for (MWWorld::Scene::CellStoreCollection::iterator iter = activeCells.begin(); iter != activeCells.end(); iter++)
+        {
+            ESM::Cell iterCell = *(*iter)->getCell();
+            for (ESM::Cell cell : *cells)
+            {
+                if (cellController->isSameCell(iterCell, cell))
+                {
+                    activeToReset.insert(*iter);
+                    break;
+                }
+            }
+        }
+
+        if (!activeToReset.empty())
+        {
+            typedef std::pair<Ptr, CellStore*> returnPtr;
+            std::map<Ptr, CellStore*> moveBack;
+            for (MWWorld::Scene::CellStoreCollection::iterator iter = activeToReset.begin(); iter != activeToReset.end(); iter++)
+            {
+                ESM::Cell iterCell = *(*iter)->getCell();
+                MWWorld::CellStore * cellStore = cellController->getCellStore(iterCell);
+
+                cellStore->returnFromOtherCells();
+                std::vector<Ptr> movedRefs = cellStore->getMovedHere();
+                for (Ptr ref : movedRefs)
+                {
+                    moveBack.insert(returnPtr(ref, cellStore));
+                }
+            }
+
+            for (MWWorld::Scene::CellStoreCollection::iterator iter = activeCells.begin(); iter != activeCells.end(); iter++)
+            {
+                ESM::Cell iterCell = *(*iter)->getCell();
+                MWWorld::CellStore * cellStore = cellController->getCellStore(iterCell);
+                
+                mWorldScene->unloadCell(iter);
+                cellController->getCell(iterCell)->uninitializeLocalActors();
+                cellController->getCell(iterCell)->uninitializeDedicatedActors();
+
+                if (activeToReset.count(*iter) > 0)
+                {
+                    cellStore->clear();
+                    LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Resetting cell %s!", iterCell.getDescription().c_str());
+
+                }
+                
+                
+            }
+
+            ESM::CellId pCellId = getPlayerPtr().getCell()->getCell()->getCellId();
+
+            changeToCell(pCellId, getPlayerPtr().getRefData().getPosition(), false, true);
+
+            for (returnPtr ret : moveBack)
+            {
+                ret.first.getCell()->moveTo(ret.first, ret.second);
+                cellController->getCell(*ret.second->getCell())->initializeDedicatedActor(ret.first);
+            }
+        }
+        else
+        {
+            for (ESM::Cell cell : *cells)
+            {
+                MWWorld::CellStore * cellStore = cellController->getCellStore(cell);
+                cellStore->clear();
+            }
+        }
     }
     /*
         End of tes3mp addition
diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp
index f98b3473b..0ab306220 100644
--- a/apps/openmw/mwworld/worldimp.hpp
+++ b/apps/openmw/mwworld/worldimp.hpp
@@ -677,7 +677,17 @@ namespace MWWorld
 
                 Make it possible to check whether a cell is active
             */
-            bool isCellActive(MWWorld::CellStore* cell) override;
+            bool isCellActive(ESM::Cell cell) override;
+            /*
+                End of tes3mp addition
+            */
+
+            /*
+                Start of tes3mp addition
+
+                Make it possible to reload active cells (e.g. for CellReset)
+            */
+            void reloadCells(std::vector<ESM::Cell> * cells) override;
             /*
                 End of tes3mp addition
             */