diff --git a/apps/openmw-mp/Script/Functions/Worldstate.cpp b/apps/openmw-mp/Script/Functions/Worldstate.cpp index 28685577c..1186ad4be 100644 --- a/apps/openmw-mp/Script/Functions/Worldstate.cpp +++ b/apps/openmw-mp/Script/Functions/Worldstate.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "Worldstate.hpp" using namespace std; @@ -158,11 +160,22 @@ void WorldstateFunctions::AddEnforcedCollisionRefId(const char *refId) noexcept writeWorldstate.enforcedCollisionRefIds.push_back(refId); } +void WorldstateFunctions::AddCellToReset(const char *cellDescription) noexcept +{ + ESM::Cell cell = Utils::getCellFromDescription(cellDescription); + writeWorldstate.cellsToReset.push_back(cell); +} + void WorldstateFunctions::ClearEnforcedCollisionRefIds() noexcept { writeWorldstate.enforcedCollisionRefIds.clear(); } +void WorldstateFunctions::ClearCellsToReset() noexcept +{ + writeWorldstate.cellsToReset.clear(); +} + void WorldstateFunctions::SaveMapTileImageFile(unsigned int index, const char *filePath) noexcept { if (index >= readWorldstate->mapTiles.size()) @@ -276,6 +289,20 @@ void WorldstateFunctions::SendWorldRegionAuthority(unsigned short pid) noexcept packet->Send(true); } +void WorldstateFunctions::SendCellReset(unsigned short pid, bool sendToOtherPlayers) noexcept +{ + mwmp::WorldstatePacket *packet = mwmp::Networking::get().getWorldstatePacketController()->GetPacket(ID_CELL_RESET); + + Player *player; + GET_PLAYER(pid, player, ); + + writeWorldstate.guid = player->guid; + + packet->setWorldstate(&writeWorldstate); + + packet->Send(sendToOtherPlayers); +} + // All methods below are deprecated versions of methods from above diff --git a/apps/openmw-mp/Script/Functions/Worldstate.hpp b/apps/openmw-mp/Script/Functions/Worldstate.hpp index 3728d84a9..23eb31dc5 100644 --- a/apps/openmw-mp/Script/Functions/Worldstate.hpp +++ b/apps/openmw-mp/Script/Functions/Worldstate.hpp @@ -55,6 +55,10 @@ {"SendWorldCollisionOverride", WorldstateFunctions::SendWorldCollisionOverride},\ {"SendWorldRegionAuthority", WorldstateFunctions::SendWorldRegionAuthority},\ \ + {"AddCellToReset", WorldstateFunctions::AddCellToReset},\ + {"ClearCellsToReset", WorldstateFunctions::ClearCellsToReset},\ + {"SendCellsToReset", WorldstateFunctions::SendCellReset},\ + \ {"ReadLastWorldstate", WorldstateFunctions::ReadLastWorldstate},\ {"CopyLastWorldstateToStore", WorldstateFunctions::CopyLastWorldstateToStore} @@ -302,6 +306,13 @@ public: */ static void AddEnforcedCollisionRefId(const char* refId) noexcept; + /** + * \brief Add a cell with given cellDescription to the list of cells that should be reset on the client. + * + * \return void + */ + static void AddCellToReset(const char * cellDescription) noexcept; + /** * \brief Clear the list of refIdsd for which collision should be enforced irrespective * of other settings. @@ -310,6 +321,13 @@ public: */ static void ClearEnforcedCollisionRefIds() noexcept; + /** + * \brief Clear the list of cells which should be reset on the client. + * + * \return void + */ + static void ClearCellsToReset() noexcept; + /** * \brief Save the .png image data of the map tile at a certain index in the read worldstate's * map changes. @@ -342,6 +360,14 @@ public: */ static void SendWorldRegionAuthority(unsigned short pid) noexcept; + /** + * \brief Send a CellReset packet with a list of cells, + * + * \param pid The player ID attached to the packet. + * \return void + */ + static void SendCellReset(unsigned short pid, bool sendToOtherPlayers) noexcept; + /** * \brief Send a WorldMap packet with the current set of map changes in the write-only * worldstate. diff --git a/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp b/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp index 9cca7b3d0..1a24cb0e0 100644 --- a/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp +++ b/apps/openmw/mwmp/processors/worldstate/ProcessorCellReset.hpp @@ -15,7 +15,20 @@ namespace mwmp virtual void Do(WorldstatePacket &packet, Worldstate &worldstate) { - // Placeholder + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_CELL_RESET"); + CellController* cellController = Main::get().getCellController(); + + 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()); + } } }; } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index fec2ac35c..5327a0898 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1177,4 +1177,50 @@ namespace MWWorld } } } + + /* + Start of tes3mp addition + + Make it possible to clear cell data (e.g. to reset cells) + */ + void CellStore::clear() + { + if (mState != State_Unloaded) + { + mState = State_Unloaded; + + mIds.clear(); + + mActivators.mList.clear(); + mPotions.mList.clear(); + mAppas.mList.clear(); + mArmors.mList.clear(); + mBooks.mList.clear(); + mClothes.mList.clear(); + mContainers.mList.clear(); + mCreatures.mList.clear(); + mDoors.mList.clear(); + mIngreds.mList.clear(); + mCreatureLists.mList.clear(); + mItemLists.mList.clear(); + 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(); + + mMovedHere.clear(); + mMovedToAnotherCell.clear(); + mMergedRefs.clear(); + + mFogState = NULL; + } + } + /* + End of tes3mp addition + */ } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f6cfc6c21..3975c698d 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -435,6 +435,16 @@ namespace MWWorld void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. + /* + Start of tes3mp addition + + Make it possible to clear cell data (e.g. to reset cells). + */ + void clear (); + /* + End of tes3mp addition + */ + private: /// Run through references and store IDs diff --git a/components/openmw-mp/Base/BaseWorldstate.hpp b/components/openmw-mp/Base/BaseWorldstate.hpp index 8860a0ec8..0b8ca4e0c 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -232,6 +232,8 @@ namespace mwmp std::vector spellRecords; std::vector weaponRecords; + std::vector cellsToReset; + bool isValid; }; } diff --git a/components/openmw-mp/Packets/Worldstate/PacketCellReset.cpp b/components/openmw-mp/Packets/Worldstate/PacketCellReset.cpp index d89f789f6..f5f5968cd 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketCellReset.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketCellReset.cpp @@ -13,5 +13,22 @@ void PacketCellReset::Packet(RakNet::BitStream *bs, bool send) { WorldstatePacket::Packet(bs, send); - // Placeholder + uint32_t cellCount; + + if (send) + cellCount = static_cast(worldstate->cellsToReset.size()); + + RW(cellCount, send); + + if (!send) + { + worldstate->cellsToReset.clear(); + worldstate->cellsToReset.resize(cellCount); + } + + for (auto &&cellToReset : worldstate->cellsToReset) + { + RW(cellToReset.mData, send, true); + RW(cellToReset.mName, send, true); + } }