diff --git a/apps/openmw-mp/Worldstate.cpp b/apps/openmw-mp/Worldstate.cpp index d73e453ab..0ca1598a0 100644 --- a/apps/openmw-mp/Worldstate.cpp +++ b/apps/openmw-mp/Worldstate.cpp @@ -173,8 +173,17 @@ void MapTiles::processUpdate() void MapTiles::addMapTile(const MapTile &mapTile) { - mwmp::Networking::get().get().getServerWorldstate()->mapChanges.mapTiles.push_back(mapTile.mapTile); - setChanged(); + if (mapTile.mapTile.imageData.size() > mwmp::maxImageDataSize) + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Error loading image file for map tile: " + "%i, %i has a size of %i, which is over the maximum allowed of %i!", + mapTile.mapTile.x, mapTile.mapTile.y, mapTile.mapTile.imageData.size(), mwmp::maxImageDataSize); + } + else + { + mwmp::Networking::get().get().getServerWorldstate()->mapChanges.mapTiles.push_back(mapTile.mapTile); + setChanged(); + } } MapTile MapTiles::getMapTile(int id) const diff --git a/apps/openmw/mwmp/Worldstate.cpp b/apps/openmw/mwmp/Worldstate.cpp index 9af7369b9..801dc7dea 100644 --- a/apps/openmw/mwmp/Worldstate.cpp +++ b/apps/openmw/mwmp/Worldstate.cpp @@ -31,21 +31,43 @@ Networking *Worldstate::getNetworking() return mwmp::Main::get().getNetworking(); } -void Worldstate::sendMapExplored(int x, int y, const std::vector& imageData) +bool Worldstate::containsExploredMapTile(int cellX, int cellY) +{ + for (const auto &mapTile : exploredMapTiles) + { + if (mapTile.x == cellX && mapTile.y == cellY) + return true; + } + + return false; +} + +void Worldstate::markExploredMapTile(int cellX, int cellY) +{ + mwmp::BaseMapTile exploredTile; + exploredTile.x = cellX; + exploredTile.y = cellY; + exploredMapTiles.push_back(exploredTile); +} + +void Worldstate::sendMapExplored(int cellX, int cellY, const std::vector& imageData) { mapChanges.mapTiles.clear(); mwmp::BaseMapTile mapTile; - mapTile.x = x; - mapTile.y = y; + mapTile.x = cellX; + mapTile.y = cellY; mapTile.imageData = imageData; - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_PLAYER_MAP with x: %i, y: %i", x, y); + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Sending ID_PLAYER_MAP with x: %i, y: %i", cellX, cellY); mapChanges.mapTiles.push_back(mapTile); getNetworking()->getWorldstatePacket(ID_WORLD_MAP)->setWorldstate(this); getNetworking()->getWorldstatePacket(ID_WORLD_MAP)->Send(); + + // Keep this tile marked as explored so we don't send any more packets for it + markExploredMapTile(mapTile.x, mapTile.y); } void Worldstate::setMapExplored() @@ -58,5 +80,8 @@ void Worldstate::setMapExplored() MWBase::Environment::get().getWindowManager()->addVisitedLocation(cellStore->getCell()->mName, mapTile.x, mapTile.y); MWBase::Environment::get().getWindowManager()->setGlobalMapImage(mapTile.x, mapTile.y, mapTile.imageData); + + // Keep this tile marked as explored so we don't send any more packets for it + markExploredMapTile(mapTile.x, mapTile.y); } } diff --git a/apps/openmw/mwmp/Worldstate.hpp b/apps/openmw/mwmp/Worldstate.hpp index df44372c1..d21a89e5e 100644 --- a/apps/openmw/mwmp/Worldstate.hpp +++ b/apps/openmw/mwmp/Worldstate.hpp @@ -13,11 +13,18 @@ namespace mwmp Worldstate(); virtual ~Worldstate(); + bool containsExploredMapTile(int cellX, int cellY); + + void markExploredMapTile(int cellX, int cellY); + void setMapExplored(); - void sendMapExplored(int x, int y, const std::vector& imageData); + void sendMapExplored(int cellX, int cellY, const std::vector& imageData); private: + + std::vector exploredMapTiles; + Networking *getNetworking(); }; diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 218ef7704..7f088b94e 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -636,32 +636,42 @@ namespace MWRender /* Start of tes3mp addition - Send an ID_PLAYER_MAP packet with this map tile to the server + Send an ID_PLAYER_MAP packet with this map tile to the server, but only if: + 1) We have recorded the exterior cell corresponding to this tile's coordinates + 2) The tile has not previously been marked as explored in this client's mwmp::Worldstate */ if (originToCellX.count(imageDest.mX) > 0 && originToCellY.count(imageDest.mY) > 0) { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "New global map tile corresponds to cell %i, %i", originToCellX.at(imageDest.mX), originToCellY.at(imageDest.mY)); + int cellX = originToCellX.at(imageDest.mX); + int cellY = originToCellY.at(imageDest.mY); - osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); - if (!readerwriter) + mwmp::Worldstate *worldstate = mwmp::Main::get().getNetworking()->getWorldstate(); + + if (!worldstate->containsExploredMapTile(cellX, cellY)) { - std::cerr << "Error: Can't write temporary map image, no '" << "png" << "' readerwriter found" << std::endl; - return; - } + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "New global map tile corresponds to cell %i, %i", originToCellX.at(imageDest.mX), originToCellY.at(imageDest.mY)); - std::ostringstream ostream; + osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png"); + if (!readerwriter) + { + std::cerr << "Error: Can't write temporary map image, no '" << "png" << "' readerwriter found" << std::endl; + return; + } - osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*imageDest.mImage, ostream); - - if (!result.success()) - { - std::cerr << "Error: Can't write temporary map image: " << result.message() << " code " << result.status() << std::endl; - } + std::ostringstream ostream; - std::string stringData = ostream.str(); - std::vector vectorData = std::vector(stringData.begin(), stringData.end()); + osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*imageDest.mImage, ostream); - mwmp::Main::get().getNetworking()->getWorldstate()->sendMapExplored(originToCellX.at(imageDest.mX), originToCellY.at(imageDest.mY), vectorData); + if (!result.success()) + { + std::cerr << "Error: Can't write temporary map image: " << result.message() << " code " << result.status() << std::endl; + } + + std::string stringData = ostream.str(); + std::vector vectorData = std::vector(stringData.begin(), stringData.end()); + + worldstate->sendMapExplored(cellX, cellY, vectorData); + } } /* End of tes3mp addition diff --git a/components/openmw-mp/Base/BaseWorldstate.hpp b/components/openmw-mp/Base/BaseWorldstate.hpp index cd15ee940..3cbf785ec 100644 --- a/components/openmw-mp/Base/BaseWorldstate.hpp +++ b/components/openmw-mp/Base/BaseWorldstate.hpp @@ -9,6 +9,8 @@ namespace mwmp { + static const int maxImageDataSize = 1800; + struct BaseMapTile { int x; diff --git a/components/openmw-mp/Packets/Worldstate/PacketWorldMap.cpp b/components/openmw-mp/Packets/Worldstate/PacketWorldMap.cpp index 36b5c4303..43b72bb64 100644 --- a/components/openmw-mp/Packets/Worldstate/PacketWorldMap.cpp +++ b/components/openmw-mp/Packets/Worldstate/PacketWorldMap.cpp @@ -1,4 +1,5 @@ #include +#include #include "PacketWorldMap.hpp" using namespace std; @@ -31,17 +32,25 @@ void PacketWorldMap::Packet(RakNet::BitStream *bs, bool send) RW(mapTile.x, send); RW(mapTile.y, send); - uint32_t imageDataCount; + uint32_t imageDataSize; if (send) - imageDataCount = static_cast(mapTile.imageData.size()); + imageDataSize = static_cast(mapTile.imageData.size()); - RW(imageDataCount, send); + RW(imageDataSize, send); + + if (imageDataSize > mwmp::maxImageDataSize) + { + LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Processed invalid ID_WORLD_MAP packet where tile %i, %i had an imageDataSize of %i", + mapTile.x, mapTile.y, imageDataSize); + LOG_APPEND(Log::LOG_ERROR, "- The packet was ignored after that point"); + return; + } if (!send) { mapTile.imageData.clear(); - mapTile.imageData.resize(imageDataCount); + mapTile.imageData.resize(imageDataSize); } for (auto &&imageChar : mapTile.imageData) diff --git a/tes3mp-credits.md b/tes3mp-credits.md index 5660591e1..6811a9bc1 100644 --- a/tes3mp-credits.md +++ b/tes3mp-credits.md @@ -49,6 +49,7 @@ Special thanks (in alphabetical order) Camul David Wery DestinedToDie + Donovan Ando Gluka Goodevil greetasdf