From fcd6d3cfe9bf1a05fd6d25c6caab3c4adf38ac01 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 23 Jun 2012 11:26:18 -0300 Subject: [PATCH] Minimap fixes * Fix infinite loop while loading minimap * Fix errors in FileStream class * Remake OTCM map format * Fixes in UIMap --- modules/game_minimap/minimap.lua | 3 +- src/framework/core/filestream.cpp | 62 +++++++------- src/framework/core/filestream.h | 11 +-- src/otclient/core/item.cpp | 5 ++ src/otclient/core/item.h | 3 +- src/otclient/core/map.cpp | 138 ++++++++++++++++++++---------- src/otclient/core/map.h | 5 ++ src/otclient/core/tile.cpp | 10 +++ src/otclient/core/tile.h | 1 + src/otclient/ui/uimap.cpp | 7 +- 10 files changed, 162 insertions(+), 83 deletions(-) diff --git a/modules/game_minimap/minimap.lua b/modules/game_minimap/minimap.lua index 41ecd132..334abd39 100644 --- a/modules/game_minimap/minimap.lua +++ b/modules/game_minimap/minimap.lua @@ -37,10 +37,9 @@ function Minimap.init() Keyboard.bindKeyDown('Ctrl+M', Minimap.toggle) minimapButton = TopMenu.addGameToggleButton('minimapButton', tr('Minimap') .. ' (Ctrl+M)', 'minimap.png', Minimap.toggle) - minimapButton:setOn(false) + minimapButton:setOn(true) minimapWindow = loadUI('minimap.otui', GameInterface.getRightPanel()) - minimapWindow:setOn(true) minimapWidget = minimapWindow:recursiveGetChildById('minimap') minimapWidget:setAutoViewMode(false) diff --git a/src/framework/core/filestream.cpp b/src/framework/core/filestream.cpp index 58ecdf44..58390f12 100644 --- a/src/framework/core/filestream.cpp +++ b/src/framework/core/filestream.cpp @@ -48,9 +48,8 @@ void FileStream::cache() PHYSFS_seek(m_fileHandle, 0); int size = PHYSFS_fileLength(m_fileHandle); m_data.resize(size); - int res = PHYSFS_read(m_fileHandle, &m_data[0], size, 1); - if(res == -1) - throwError("unable to read file data"); + if(PHYSFS_read(m_fileHandle, &m_data[0], size, 1) == -1) + throwError("unable to read file data", true); close(); } @@ -59,7 +58,7 @@ void FileStream::close() { if(m_fileHandle) { if(!PHYSFS_close(m_fileHandle)) - throwError("close failed"); + throwError("close failed", true); m_fileHandle = nullptr; } else { m_data.clear(); @@ -70,7 +69,7 @@ void FileStream::close() void FileStream::flush() { if(m_fileHandle && PHYSFS_flush(m_fileHandle) == 0) - throwError("flush failed"); + throwError("flush failed", true); } int FileStream::read(void *buffer, uint32 size, uint32 nmemb) @@ -78,7 +77,7 @@ int FileStream::read(void *buffer, uint32 size, uint32 nmemb) if(m_fileHandle) { int res = PHYSFS_read(m_fileHandle, buffer, size, nmemb); if(res == -1) - throwError("read failed"); + throwError("read failed", true); return res; } else { uint maxReadPos = m_data.size()-1; @@ -95,17 +94,17 @@ int FileStream::read(void *buffer, uint32 size, uint32 nmemb) } } -void FileStream::write(void *buffer, uint32 count) +void FileStream::write(const void *buffer, uint32 count) { if(PHYSFS_write(m_fileHandle, buffer, 1, count) != count) - throwError("write failed"); + throwError("write failed", true); } void FileStream::seek(uint32 pos) { if(m_fileHandle) { if(!PHYSFS_seek(m_fileHandle, pos)) - throwError("seek failed"); + throwError("seek failed", true); } else { if(pos > m_data.size()) throwError("seek failed"); @@ -139,7 +138,7 @@ uint8 FileStream::getU8() uint8 v = 0; if(m_fileHandle) { if(PHYSFS_read(m_fileHandle, &v, 1, 1) != 1) - throwError("read failed"); + throwError("read failed", true); } else { if(m_pos+1 > m_data.size()) throwError("read failed"); @@ -155,7 +154,7 @@ uint16 FileStream::getU16() uint16 v = 0; if(m_fileHandle) { if(PHYSFS_readULE16(m_fileHandle, &v) == 0) - throwError("read failed"); + throwError("read failed", true); } else { if(m_pos+2 > m_data.size()) throwError("read failed"); @@ -171,7 +170,7 @@ uint32 FileStream::getU32() uint32 v = 0; if(m_fileHandle) { if(PHYSFS_readULE32(m_fileHandle, &v) == 0) - throwError("read failed"); + throwError("read failed", true); } else { if(m_pos+4 > m_data.size()) throwError("read failed"); @@ -187,7 +186,7 @@ uint64 FileStream::getU64() uint64 v = 0; if(m_fileHandle) { if(PHYSFS_readULE64(m_fileHandle, (PHYSFS_uint64*)&v) == 0) - throwError("read failed"); + throwError("read failed", true); } else { if(m_pos+8 > m_data.size()) throwError("read failed"); @@ -200,12 +199,12 @@ uint64 FileStream::getU64() std::string FileStream::getString() { std::string str; - int len = getU16(); + uint16 len = getU16(); if(len > 0 && len < 8192) { char buffer[8192]; if(m_fileHandle) { if(PHYSFS_read(m_fileHandle, buffer, 1, len) == 0) - throwError("read failed"); + throwError("read failed", true); else str = std::string(buffer, len); } else { @@ -217,42 +216,45 @@ std::string FileStream::getString() str = std::string((char*)&m_data[m_pos], len); m_pos += len; } - } else { - } + } else if(len != 0) + throwError("read failed because string is too big"); return str; } void FileStream::addU8(uint8 v) { if(PHYSFS_write(m_fileHandle, &v, 1, 1) != 1) - throwError("write failed"); + throwError("write failed", true); } -void FileStream::addU16(uint8 v) +void FileStream::addU16(uint16 v) { if(PHYSFS_writeULE16(m_fileHandle, v) == 0) - throwError("write failed"); + throwError("write failed", true); } -void FileStream::addU32(uint8 v) +void FileStream::addU32(uint32 v) { if(PHYSFS_writeULE32(m_fileHandle, v) == 0) - throwError("write failed"); + throwError("write failed", true); } -void FileStream::addU64(uint8 v) +void FileStream::addU64(uint64 v) { if(PHYSFS_writeULE64(m_fileHandle, v) == 0) - throwError("write failed"); + throwError("write failed", true); } -void FileStream::throwError(const std::string& message) +void FileStream::addString(const std::string& v) +{ + addU16(v.length()); + write(v.c_str(), v.length()); +} + +void FileStream::throwError(const std::string& message, bool physfsError) { std::string completeMessage = stdext::format("in file '%s': %s", m_name, message); - if(m_fileHandle) { - const char *errorMessage = PHYSFS_getLastError(); - if(errorMessage) - completeMessage += std::string(": ") + errorMessage; - } + if(physfsError) + completeMessage += std::string(": ") + PHYSFS_getLastError(); stdext::throw_exception(completeMessage); } diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h index dbfe40f4..93306841 100644 --- a/src/framework/core/filestream.h +++ b/src/framework/core/filestream.h @@ -38,7 +38,7 @@ public: void cache(); void close(); void flush(); - void write(void *buffer, uint count); + void write(const void *buffer, uint count); int read(void *buffer, uint size, uint nmemb = 1); void seek(uint pos); void skip(uint len); @@ -53,13 +53,14 @@ public: std::string getString(); void addU8(uint8 v); - void addU16(uint8 v); - void addU32(uint8 v); - void addU64(uint8 v); + void addU16(uint16 v); + void addU32(uint32 v); + void addU64(uint64 v); + void addString(const std::string& v); private: void checkWrite(); - void throwError(const std::string& message); + void throwError(const std::string& message, bool physfsError = false); std::string m_name; PHYSFS_File *m_fileHandle; diff --git a/src/otclient/core/item.cpp b/src/otclient/core/item.cpp index 27d2be7c..eb4e7ee4 100644 --- a/src/otclient/core/item.cpp +++ b/src/otclient/core/item.cpp @@ -196,6 +196,11 @@ void Item::setOtbId(uint16 id) m_id = m_datType->getId(); } +bool Item::isValid() +{ + return g_things.isValidDatId(m_id, DatItemCategory); +} + bool Item::unserializeAttr(FileStreamPtr fin) { uint8 attrType; diff --git a/src/otclient/core/item.h b/src/otclient/core/item.h index 11ab1094..9958d3ea 100644 --- a/src/otclient/core/item.h +++ b/src/otclient/core/item.h @@ -95,6 +95,7 @@ public: int getCount() { return m_countOrSubType; } uint32 getId() { return m_id; } std::string getName() { return m_name; } + bool isValid(); ItemPtr asItem() { return std::static_pointer_cast(shared_from_this()); } bool isItem() { return true; } @@ -104,8 +105,6 @@ public: bool unserializeItemNode(FileStreamPtr fin, uint8) { return unserializeAttr(fin); } void readAttr(AttrTypes_t attrType, FileStreamPtr fin); - bool isMoveable() { return false; } - private: uint16 m_id; uint8 m_countOrSubType; diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index 77d7394f..a6f91897 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -284,61 +284,112 @@ bool Map::loadOtbm(const std::string& fileName) bool Map::loadOtcm(const std::string& fileName) { - if(!g_resources.fileExists(fileName)) { - g_logger.error(stdext::format("Unable to load map '%s'", fileName)); - return false; - } + try { + FileStreamPtr fin = g_resources.openFile(fileName); - std::stringstream in; - g_resources.loadFile(fileName, in); + uint32 signature = fin->getU32(); + if(signature != OTCM_SIGNATURE) + stdext::throw_exception("invalid otcm file"); - while(!in.eof()) { - Position pos; - in.read((char*)&pos, sizeof(pos)); - - uint16 id; - in.read((char*)&id, sizeof(id)); - while(id != 0xFFFF) { - ItemPtr item = Item::create(id); - if(item->isStackable() || item->isFluidContainer() || item->isFluid()) { - uint8 countOrSubType; - in.read((char*)&countOrSubType, sizeof(countOrSubType)); - item->setCountOrSubType(countOrSubType); + uint16 version = fin->getU16(); + switch(version) { + case 1: { + fin->getString(); // description + uint32 datSignature = fin->getU32(); + fin->getU16(); // protocol version + fin->getString(); // world name + + if(datSignature != g_things.getDatSignature()) + g_logger.warning("otcm map loaded is was created with a different dat signature"); + + break; } - addThing(item, pos, 255); - in.read((char*)&id, sizeof(id)); + default: + stdext::throw_exception("otcm version not supported"); + break; } - } - return true; + while(true) { + Position pos; + pos.x = fin->getU16(); + pos.y = fin->getU16(); + pos.z = fin->getU8(); + + // end of file + if(!pos.isValid()) + break; + + while(true) { + uint16 id = fin->getU16(); + + // end of tile + if(id == 0xFFFF) + break; + + uint8 countOrSubType = fin->getU8(); + + ItemPtr item = Item::create(id); + if(item->isStackable() || item->isFluidContainer() || item->isFluid()) + item->setCountOrSubType(countOrSubType); + + if(item->isValid()) + addThing(item, pos, 255); + } + } + + fin->close(); + return true; + } catch(stdext::exception& e) { + g_logger.error(stdext::format("failed to load OTCM map: %s", e.what())); + return false; + } } void Map::saveOtcm(const std::string& fileName) { - std::stringstream out; - - uint16 id; - for(auto& pair : m_tiles) { - Position pos = pair.first; - TilePtr tile = pair.second; - if(!tile || tile->isEmpty()) - continue; - out.write((char*)&pos, sizeof(pos)); - for(const ThingPtr& thing : tile->getThings()) { - if(ItemPtr item = thing->asItem()) { - id = item->getId(); - out.write((char*)&id, sizeof(id)); - if(item->isStackable() || item->isFluidContainer() || item->isFluid()) { - uint8 countOrSubType = item->getCountOrSubType(); - out.write((char*)&countOrSubType, sizeof(countOrSubType)); - } + try { + FileStreamPtr fin = g_resources.createFile(fileName); + + fin->addU32(OTCM_SIGNATURE); + fin->addU16(OTCM_VERSION); + fin->addString("OTCM 1.0"); + fin->addU32(g_things.getDatSignature()); + fin->addU16(g_game.getProtocolVersion()); + fin->addString(g_game.getWorldName()); + + for(auto& pair : m_tiles) { + TilePtr tile = pair.second; + if(!tile || tile->isEmpty()) + continue; + + Position pos = pair.first; + fin->addU16(pos.x); + fin->addU16(pos.y); + fin->addU8(pos.z); + + const auto& list = tile->getThings(); + auto first = std::find_if(list.begin(), list.end(), [](const ThingPtr& thing) { return thing->isItem(); }); + for(auto it = first, end = list.end(); it != end; ++it) { + ItemPtr item = (*it)->asItem(); + fin->addU16(item->getId()); + fin->addU8(item->getCountOrSubType()); } + + // end of tile + fin->addU16(0xFFFF); } - } - id = 0xFFFF; - out.write((char*)&id, sizeof(id)); - g_resources.saveFile(fileName, out); + // end of file + Position invalidPos; + fin->addU16(invalidPos.x); + fin->addU16(invalidPos.y); + fin->addU8(invalidPos.z); + + fin->flush(); + fin->close(); + } catch(stdext::exception& e) { + g_logger.error(stdext::format("failed to save OTCM map: %s", e.what())); + } } void Map::clean() @@ -582,6 +633,7 @@ std::vector Map::getSpectatorsInRangeEx(const Position& centerPos, maxZRange = Otc::MAX_Z; } + //TODO: optimize //TODO: get creatures from other floors corretly //TODO: delivery creatures in distance order diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index efc1081c..fe6f3b45 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -75,6 +75,11 @@ enum OTBM_NodeTypes_t OTBM_WAYPOINT = 16 }; +enum { + OTCM_SIGNATURE = 0x12345678, + OTCM_VERSION = 1, +}; + //@bindsingleton g_map class Map { diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index 275f5ee5..a436460c 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -253,6 +253,16 @@ ThingPtr Tile::getTopThing() return m_things[m_things.size() - 1]; } +std::vector Tile::getItems() +{ + std::vector items; + for(const ThingPtr& thing : m_things) { + if(ItemPtr item = thing->asItem()) + items.push_back(item); + } + return items; +} + std::vector Tile::getCreatures() { std::vector creatures; diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index 34e845e5..586502d2 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -78,6 +78,7 @@ public: const Position& getPosition() { return m_position; } int getDrawElevation() { return m_drawElevation; } + std::vector getItems(); std::vector getCreatures(); const std::vector& getThings() { return m_things; } ItemPtr getGround(); diff --git a/src/otclient/ui/uimap.cpp b/src/otclient/ui/uimap.cpp index c6ca4ee3..9f90191e 100644 --- a/src/otclient/ui/uimap.cpp +++ b/src/otclient/ui/uimap.cpp @@ -151,9 +151,14 @@ void UIMap::onGeometryChange(const Rect& oldRect, const Rect& newRect) void UIMap::updateVisibleDimension() { int dimensionHeight = m_zoom; + + float ratio = 1; + if(!m_mapRect.isEmpty()) + ratio = m_mapRect.size().ratio(); + if(dimensionHeight % 2 == 0) dimensionHeight += 1; - int dimensionWidth = m_zoom * m_mapRect.size().ratio(); + int dimensionWidth = m_zoom * ratio; if(dimensionWidth % 2 == 0) dimensionWidth += 1;