From 85b52fbdfda0cc34bc288e8e216b8ace147b53f4 Mon Sep 17 00:00:00 2001 From: niczkx Date: Wed, 8 Aug 2012 07:59:38 -0600 Subject: [PATCH] More work on OTBM saving (now it can save binary map w/o spawns and houses) w00t, the 1000th commit --- src/framework/util/point.h | 3 ++ src/otclient/item.cpp | 12 ++++++- src/otclient/item.h | 1 + src/otclient/mapio.cpp | 68 +++++++++++++++++++++++++++----------- src/otclient/towns.h | 3 +- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/framework/util/point.h b/src/framework/util/point.h index a22eb019..57dc1889 100644 --- a/src/framework/util/point.h +++ b/src/framework/util/point.h @@ -61,6 +61,9 @@ public: TPoint operator/(float v) const { return TPoint(x/v, y/v); } TPoint& operator/=(float v) { x/=v; y/=v; return *this; } + TPoint operator&(int a) { return TPoint(x & a, y & a); } + TPoint& operator&=(int a) { x &= a; y &= a; return *this; } + bool operator<=(const TPoint&other) const { return x<=other.x && y<=other.y; } bool operator>=(const TPoint&other) const { return x>=other.x && y>=other.y; } bool operator<(const TPoint&other) const { return xstartNode(OTBM_ITEM); + out->writeU16(getId()); + out->writeU8(ATTR_COUNT); out->writeU8(getCount()); - out->writeU8(ATTR_CHARGES); + out->writeU8(ATTR_CHARGES);; out->writeU16(getCountOrSubType()); Position dest = m_attribs.get(ATTR_TELE_DEST); @@ -298,6 +301,8 @@ void Item::serializeItem(const BinaryWriteTreePtr& out) out->writeU8(ATTR_UNIQUE_ID); out->writeU16(uid); } + + out->endNode(); } int Item::getSubType() @@ -321,6 +326,11 @@ bool Item::isMoveable() return !rawGetThingType()->isNotMoveable(); } +bool Item::isGround() +{ + return rawGetThingType()->isGround(); +} + ItemPtr Item::clone() { ItemPtr item = ItemPtr(new Item); diff --git a/src/otclient/item.h b/src/otclient/item.h index 3937a915..00a8e064 100644 --- a/src/otclient/item.h +++ b/src/otclient/item.h @@ -114,6 +114,7 @@ public: bool isDoor() { return m_attribs.has(ATTR_HOUSEDOORID); } bool isTeleport() { return m_attribs.has(ATTR_TELE_DEST); } bool isMoveable(); + bool isGround(); ItemPtr asItem() { return static_self_cast(); } bool isItem() { return true; } diff --git a/src/otclient/mapio.cpp b/src/otclient/mapio.cpp index 720f4c72..8d50b44d 100644 --- a/src/otclient/mapio.cpp +++ b/src/otclient/mapio.cpp @@ -215,7 +215,7 @@ void Map::loadOtbm(const std::string& fileName) void Map::saveOtbm(const std::string &fileName) { - FileStreamPtr fin = g_resources.appendFile(fileName); + FileStreamPtr fin = g_resources.createFile(fileName); if(!fin) stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName)); @@ -235,13 +235,26 @@ void Map::saveOtbm(const std::string &fileName) /// Usually when a map has empty house/spawn file it means the map is new. /// TODO: Ask the user for a map name instead of those ugly uses of substr + std::string::size_type sep_pos; std::string houseFile = getHouseFile(); std::string spawnFile = getSpawnFile(); - if(houseFile.empty() && version > 1) - houseFile = fileName.substr(fileName.find_last_of('/')) + "-houses.xml"; + std::string cpyf; + + if((sep_pos = fileName.rfind('.')) != std::string::npos && stdext::ends_with(fileName, ".otbm")) + cpyf = fileName.substr(0, sep_pos); + + if(houseFile.empty()) + houseFile = cpyf + "-houses.xml"; + if(spawnFile.empty()) - spawnFile = fileName.substr(fileName.find_last_of('/')) + "-spawns.xml"; + spawnFile = cpyf + "-spawns.xml"; + /// we only need the filename to save to, the directory should be resolved by the OTBM loader not here + if((sep_pos = spawnFile.rfind('/')) != std::string::npos) + spawnFile = spawnFile.substr(sep_pos + 1); + + if((sep_pos = houseFile.rfind('/')) != std::string::npos) + houseFile = houseFile.substr(sep_pos + 1); #if 0 if(version > 1) m_houses->save(dir + "/" + houseFile); @@ -251,6 +264,7 @@ void Map::saveOtbm(const std::string &fileName) fin->addU32(0); // file version BinaryWriteTreePtr root(new BinaryWriteTree(fin)); + root->startNode(0); { root->writeU32(version); @@ -271,7 +285,7 @@ void Map::saveOtbm(const std::string &fileName) // special one root->writeU8(OTBM_ATTR_DESCRIPTION); - root->writeString(stdext::format("Saved with %s v%d", g_app.getName(), stdext::unsafe_cast(g_app.getVersion()))); + root->writeString(stdext::format("Saved with %s v%s", g_app.getName(), g_app.getVersion())); // spawn file. root->writeU8(OTBM_ATTR_SPAWN_FILE); @@ -283,66 +297,80 @@ void Map::saveOtbm(const std::string &fileName) root->writeString(houseFile); } - /// write tiles first - root->startNode(OTBM_TILE_AREA); Position base(-1, -1, -1); + bool firstNode = true; for(uint8_t z = 0; z < Otc::MAX_Z + 1; ++z) { for(const auto& it : m_tileBlocks[z]) { const TileBlock& block = it.second; for(const TilePtr& tile : block.getTiles()) { + if(!tile) + continue; + const Position& pos = tile->getPosition(); if(!pos.isValid()) continue; - /// base position if(pos.x < base.x || pos.x >= base.x + 256 || pos.y < base.y|| pos.y >= base.y + 256 || - pos.z != base.z) + pos.z != base.z) { + if(!firstNode) + root->endNode(); /// OTBM_TILE_AREA + + root->startNode(OTBM_TILE_AREA); + firstNode = false; root->writePos(base = pos & 0xFF00); + } uint32 flags = tile->getFlags(); - if((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE) - root->startNode(OTBM_HOUSETILE); - else - root->startNode(OTBM_TILE); - root->writePoint(Point(pos.x, pos.y)); + root->startNode((flags & TILESTATE_HOUSE) == TILESTATE_HOUSE ? OTBM_HOUSETILE : OTBM_TILE); + root->writePoint(Point(pos.x, pos.y) & 0xFF); // if(tileNode->getType() == OTBM_HOUSETILE) // tileNode->writeU32(tile->getHouseId()); - /// Tile flags if(flags) { root->writeU8(OTBM_ATTR_TILE_FLAGS); root->writeU32(flags); } - /// start writing tile items for(const ItemPtr& item : tile->getItems()) { - root->startNode(OTBM_ATTR_ITEM); - item->serializeItem(root); + if(item->isGround()) { + root->writeU8(OTBM_ATTR_ITEM); + root->writeU16(item->getId()); + continue; + } + + item->serializeItem(root); } + + root->endNode(); // OTBM_TILE } } } - /// write towns + if(!firstNode) + root->endNode(); // OTBM_TILE_AREA + root->startNode(OTBM_TOWNS); for(const TownPtr& town : m_towns.getTowns()) { root->writeU32(town->getId()); root->writeString(town->getName()); root->writePos(town->getPos()); } + root->endNode(); - /// write waypoints if(version > 1) { root->startNode(OTBM_WAYPOINTS); for(const auto& it : m_waypoints) { root->writeString(it.second); root->writePos(it.first); } + root->endNode(); } } + root->endNode(); // OTBM_MAP_DATA } + root->endNode(); // 0 (root) } void Map::loadSpawns(const std::string &fileName) diff --git a/src/otclient/towns.h b/src/otclient/towns.h index 978424e9..5662f51d 100644 --- a/src/otclient/towns.h +++ b/src/otclient/towns.h @@ -56,8 +56,7 @@ public: TownPtr getTown(uint32 townId); TownList getTowns() { return m_towns; } - // Fix to segfault on exit - void clear() { m_towns.clear(); } + void clear() { m_towns.clear(); } private: TownList m_towns;