bool IOMapSerialize::loadHouseInfo(Map* map) { Database* db = Database::getInstance(); std::ostringstream query; DBResult* result = db->storeQuery("SELECT `id`, `owner`, `paid`, `warnings` FROM `houses`"); if (!result) { return false; } do { House* house = Houses::getInstance().getHouse(result->getDataInt("id")); if (house) { house->setHouseOwner(result->getDataInt("owner")); house->setPaidUntil(result->getDataInt("paid")); house->setPayRentWarnings(result->getDataInt("warnings")); } } while (result->next()); db->freeResult(result); for (const auto& it : Houses::getInstance().getHouses()) { House* house = it.second; if (house->getHouseOwner() != 0 && house->getHouseId() != 0) { query.str(""); query << "SELECT `listid`, `list` FROM `house_lists` WHERE `house_id` = " << house->getHouseId(); if ((result = db->storeQuery(query.str()))) { do { house->setAccessList(result->getDataInt("listid"), result->getDataString("list")); } while (result->next()); db->freeResult(result); } } } return true; }
bool IOMapSerialize::saveMap(Map* map) { int64_t start = OTSYS_TIME(); Database* db = Database::getInstance(); std::ostringstream query; //Start the transaction DBTransaction transaction; if (!transaction.begin()) { return false; } if (!db->executeQuery("DELETE FROM `tile_store`")) { return false; } DBInsert stmt; stmt.setQuery("INSERT INTO `tile_store` (`house_id`, `data`) VALUES "); //clear old tile data for (const auto& it : Houses::getInstance().getHouses()) { //save house items House* house = it.second; for (HouseTile* tile : house->getHouseTiles()) { PropWriteStream stream; saveTile(stream, tile); uint32_t attributesSize; const char* attributes = stream.getStream(attributesSize); if (attributesSize > 0) { query << house->getHouseId() << "," << db->escapeBlob(attributes, attributesSize); if (!stmt.addRow(query)) { return false; } } } } if (!stmt.execute()) { return false; } //End the transaction bool success = transaction.commit(); std::cout << "> Saved house items in: " << (OTSYS_TIME() - start) / (1000.) << " s" << std::endl; return success; }
bool IOMap::loadMap(Map* map, const std::string& identifier) { FileLoader f; if(!f.openFile(identifier.c_str(), false, true)) { std::stringstream ss; ss << "Could not open the file " << identifier << "."; setLastErrorString(ss.str()); return false; } uint32_t type = 0; NODE root = f.getChildNode((NODE)NULL, type); PropStream propStream; if(!f.getProps(root, propStream)) { setLastErrorString("Could not read root property."); return false; } OTBM_root_header* rootHeader; if(!propStream.GET_STRUCT(rootHeader)) { setLastErrorString("Could not read header."); return false; } uint32_t headerVersion = rootHeader->version; if(headerVersion <= 0) { //In otbm version 1 the count variable after splashes/fluidcontainers and stackables //are saved as attributes instead, this solves alot of problems with items //that is changed (stackable/charges/fluidcontainer/splash) during an update. setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if(headerVersion > 2) { setLastErrorString("Unknown OTBM version detected."); return false; } uint32_t headerMajorItems = rootHeader->majorVersionItems; if(headerMajorItems < 3) { setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if(headerMajorItems > (uint32_t)Items::dwMajorVersion) { setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } uint32_t headerMinorItems = rootHeader->minorVersionItems; if(headerMinorItems < CLIENT_VERSION_810) { setLastErrorString("This map needs an updated items.otb."); return false; } if(headerMinorItems > (uint32_t)Items::dwMinorVersion) setLastErrorString("This map needs an updated items.otb."); std::cout << "> Map size: " << rootHeader->width << "x" << rootHeader->height << "." << std::endl; map->mapWidth = rootHeader->width; map->mapHeight = rootHeader->height; NODE nodeMap = f.getChildNode(root, type); if(type != OTBM_MAP_DATA) { setLastErrorString("Could not read data node."); return false; } if(!f.getProps(nodeMap, propStream)) { setLastErrorString("Could not read map data attributes."); return false; } std::string tmp; uint8_t attribute; while(propStream.GET_UCHAR(attribute)) { switch(attribute) { case OTBM_ATTR_DESCRIPTION: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid description tag."); return false; } map->descriptions.push_back(tmp); break; } case OTBM_ATTR_EXT_SPAWN_FILE: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid spawnfile tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; } case OTBM_ATTR_EXT_HOUSE_FILE: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid housefile tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; } default: { setLastErrorString("Unknown header node."); return false; } } } std::cout << "> Map descriptions: " << std::endl; for(StringVec::iterator it = map->descriptions.begin(); it != map->descriptions.end(); ++it) std::cout << (*it) << std::endl; NODE nodeMapData = f.getChildNode(nodeMap, type); while(nodeMapData != NO_NODE) { if(f.getError() != ERROR_NONE) { setLastErrorString("Invalid map node."); return false; } if(type == OTBM_TILE_AREA) { if(!f.getProps(nodeMapData, propStream)) { setLastErrorString("Invalid map node."); return false; } OTBM_Destination_coords* area_coord; if(!propStream.GET_STRUCT(area_coord)) { setLastErrorString("Invalid map node."); return false; } int32_t base_x = area_coord->_x, base_y = area_coord->_y, base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while(nodeTile != NO_NODE) { if(f.getError() != ERROR_NONE) { setLastErrorString("Could not read node data."); return false; } if(type == OTBM_TILE || type == OTBM_HOUSETILE) { if(!f.getProps(nodeTile, propStream)) { setLastErrorString("Could not read node data."); return false; } OTBM_Tile_coords* tileCoord; if(!propStream.GET_STRUCT(tileCoord)) { setLastErrorString("Could not read tile position."); return false; } Tile* tile = NULL; Item* groundItem = NULL; uint32_t tileflags = 0; uint16_t px = base_x + tileCoord->_x, py = base_y + tileCoord->_y, pz = base_z; House* house = NULL; if(type == OTBM_HOUSETILE) { uint32_t _houseid; if(!propStream.GET_ULONG(_houseid)) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().getHouse(_houseid, true); if(!house) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); } //read tile attributes uint8_t attribute; while(propStream.GET_UCHAR(attribute)) { switch(attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if(!propStream.GET_ULONG(flags)) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) tileflags |= TILESTATE_PROTECTIONZONE; else if((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE) tileflags |= TILESTATE_NOPVPZONE; else if((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE) tileflags |= TILESTATE_PVPZONE; if((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) tileflags |= TILESTATE_NOLOGOUT; if((flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) { if(house) std::cout << "[x:" << px << ", y:" << py << ", z:" << pz << "] House tile flagged as refreshing!"; tileflags |= TILESTATE_REFRESH; } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if(!item) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if(house && item->isMoveable()) { std::cout << "[Warning - IOMap::loadMap] Movable item in house: " << house->getHouseId(); std::cout << ", item type: " << item->getID() << ", at position " << px << "/" << py << "/"; std::cout << pz << std::endl; delete item; item = NULL; } else if(tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if(item->isGroundTile()) { if(groundItem) delete groundItem; groundItem = item; } else { tile = createTile(groundItem, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } break; } default: { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown tile attribute."; setLastErrorString(ss.str()); return false; } } } NODE nodeItem = f.getChildNode(nodeTile, type); while(nodeItem) { if(type == OTBM_ITEM) { PropStream propStream; f.getProps(nodeItem, propStream); Item* item = Item::CreateItem(propStream); if(!item) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if(item->unserializeItemNode(f, nodeItem, propStream)) { if(house && item->isMoveable()) { std::cout << "[Warning - IOMap::loadMap] Movable item in house: "; std::cout << house->getHouseId() << ", item type: " << item->getID(); std::cout << ", pos " << px << "/" << py << "/" << pz << std::endl; delete item; item = NULL; } else if(tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if(item->isGroundTile()) { if(groundItem) delete groundItem; groundItem = item; } else { tile = createTile(groundItem, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } else { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to load item " << item->getID() << "."; setLastErrorString(ss.str()); delete item; item = NULL; return false; } } else { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } if(!tile) tile = createTile(groundItem, NULL, px, py, pz); tile->setFlag((tileflags_t)tileflags); map->setTile(px, py, pz, tile); } else { setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if(type == OTBM_TOWNS) { NODE nodeTown = f.getChildNode(nodeMapData, type); while(nodeTown != NO_NODE) { if(type == OTBM_TOWN) { if(!f.getProps(nodeTown, propStream)) { setLastErrorString("Could not read town data."); return false; } uint32_t townId = 0; if(!propStream.GET_ULONG(townId)) { setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townId); if(!town) { town = new Town(townId); Towns::getInstance().addTown(townId, town); } std::string townName = ""; if(!propStream.GET_STRING(townName)) { setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_Destination_coords *town_coords; if(!propStream.GET_STRUCT(town_coords)) { setLastErrorString("Could not read town coordinates."); return false; } town->setTemplePos(Position(town_coords->_x, town_coords->_y, town_coords->_z)); } else { setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if(type == OTBM_WAYPOINTS && headerVersion > 1) { NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while(nodeWaypoint != NO_NODE) { if(type == OTBM_WAYPOINT) { if(!f.getProps(nodeWaypoint, propStream)) { setLastErrorString("Could not read waypoint data."); return false; } std::string name; if(!propStream.GET_STRING(name)) { setLastErrorString("Could not read waypoint name."); return false; } OTBM_Destination_coords* waypoint_coords; if(!propStream.GET_STRUCT(waypoint_coords)) { setLastErrorString("Could not read waypoint coordinates."); return false; } map->waypoints.addWaypoint(WaypointPtr(new Waypoint(name, Position(waypoint_coords->_x, waypoint_coords->_y, waypoint_coords->_z)))); } else { setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else { setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } return true; }
bool Houses::payHouses() { if(rentPeriod == RENTPERIOD_NEVER) { return true; } uint32_t currentTime = std::time(NULL); for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it){ House* house = it->second; if(house->getHouseOwner() != 0 && house->getPaidUntil() < currentTime && house->getRent() != 0){ uint32_t ownerid = house->getHouseOwner(); Town* town = Towns::getInstance().getTown(house->getTownId()); if(!town){ #ifdef __DEBUG_HOUSES__ std::cout << "Warning: [Houses::payHouses] town = NULL, townid = " << house->getTownId() << ", houseid = " << house->getHouseId() << std::endl; #endif continue; } std::string name; if(!IOPlayer::instance()->getNameByGuid(ownerid, name)){ //player doesnt exist, remove it as house owner? //house->setHouseOwner(0); continue; } Player* player = g_game.getPlayerByName(name); if(!player){ player = new Player(name, NULL); if(!IOPlayer::instance()->loadPlayer(player, name)){ #ifdef __DEBUG__ std::cout << "Failure: [Houses::payHouses], can not load player: " << name << std::endl; #endif delete player; continue; } } Depot* depot = player->getDepot(town->getTownID(), true); // savePlayerHere is an ugly hack // to avoid saving 2 times a not online player // when items are transferred to his depot bool savePlayerHere = true; if(depot){ //get money from depot bool useAccBalance = g_config.getBool(ConfigManager::USE_ACCBALANCE) != 0; bool hasEnoughMoney = false; if(useAccBalance){ if(player->balance >= house->getRent()){ player->balance -= house->getRent(); hasEnoughMoney = true; } } else{ hasEnoughMoney = g_game.removeMoney(depot, house->getRent(), FLAG_NOLIMIT); } if(hasEnoughMoney){ uint32_t paidUntil = currentTime; switch(rentPeriod){ case RENTPERIOD_DAILY: paidUntil += 24 * 60 * 60; break; case RENTPERIOD_WEEKLY: paidUntil += 24 * 60 * 60 * 7; break; case RENTPERIOD_MONTHLY: paidUntil += 24 * 60 * 60 * 30; break; case RENTPERIOD_YEARLY: paidUntil += 24 * 60 * 60 * 365; case RENTPERIOD_NEVER: break; } house->setPaidUntil(paidUntil); } else if(currentTime >= house->getLastWarning() + 24 * 60 * 60){ if(house->getPayRentWarnings() >= 7){ house->setHouseOwner(0); // setHouseOwner will load the player, // transfer house items to his depot and then // will save it, so here should not be saved // again savePlayerHere = false; } else{ int daysLeft = 7 - house->getPayRentWarnings(); Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED); std::string period = ""; switch(rentPeriod){ case RENTPERIOD_DAILY: period = "daily"; break; case RENTPERIOD_WEEKLY: period = "weekly"; break; case RENTPERIOD_MONTHLY: period = "monthly"; break; case RENTPERIOD_YEARLY: period = "annual"; break; case RENTPERIOD_NEVER: // break; } std::stringstream warningText; warningText << "Warning! \n" << "The " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it available within " << daysLeft << " days, or you will lose this house."; letter->setText(warningText.str()); g_game.internalAddItem(depot, letter, INDEX_WHEREEVER, FLAG_NOLIMIT); house->setPayRentWarnings(house->getPayRentWarnings() + 1); house->setLastWarning(currentTime); } } } if(player->isOffline()){ if(savePlayerHere){ IOPlayer::instance()->savePlayer(player); } delete player; } } } return true; }
bool Houses::payHouses() { if (rentPeriod == RENTPERIOD_NEVER) { return true; } time_t currentTime = time(NULL); for (HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { House* house = it->second; if (house->getHouseOwner() != 0) { uint32_t ownerid = house->getHouseOwner(); Town* town = Towns::getInstance().getTown(house->getTownId()); if (!town) { #ifdef __DEBUG_HOUSES__ std::cout << "Warning: [Houses::payHouses] town = NULL, townid = " << house->getTownId() << ", houseid = " << house->getHouseId() << std::endl; #endif continue; } std::string name; if (!IOLoginData::getInstance()->getNameByGuid(ownerid, name)) { //player doesnt exist, remove it as house owner? house->setHouseOwner(0); continue; } Player* player = g_game.getPlayerByName(name); if (!player) { player = new Player(name, NULL); if (!IOLoginData::getInstance()->loadPlayer(player, name)) { #ifdef __DEBUG__ std::cout << "Failure: [Houses::payHouses], can not load player: " << name << std::endl; #endif delete player; continue; } } bool paid = false; if (player->getBankBalance() >= house->getRent()) { player->setBankBalance(player->getBankBalance() - house->getRent()); paid = true; } if (paid) { time_t paidUntil = currentTime; switch (rentPeriod) { case RENTPERIOD_DAILY: paidUntil += 24 * 60 * 60; break; case RENTPERIOD_WEEKLY: paidUntil += 24 * 60 * 60 * 7; break; case RENTPERIOD_MONTHLY: paidUntil += 24 * 60 * 60 * 30; break; case RENTPERIOD_YEARLY: paidUntil += 24 * 60 * 60 * 365; break; default: break; } house->setPaidUntil(paidUntil); } else { if (house->getPayRentWarnings() < 7) { int32_t daysLeft = 7 - house->getPayRentWarnings(); Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED); std::string period = ""; switch (rentPeriod) { case RENTPERIOD_DAILY: period = "daily"; break; case RENTPERIOD_WEEKLY: period = "weekly"; break; case RENTPERIOD_MONTHLY: period = "monthly"; break; case RENTPERIOD_YEARLY: period = "annual"; break; default: break; } std::ostringstream ss; ss << "Warning! \nThe " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it within " << daysLeft << " days or you will lose this house."; letter->setText(ss.str()); g_game.internalAddItem(player->getInbox(), letter, INDEX_WHEREEVER, FLAG_NOLIMIT); house->setPayRentWarnings(house->getPayRentWarnings() + 1); } else { house->setHouseOwner(0, true, player); } } if (player->isOffline()) { IOLoginData::getInstance()->savePlayer(player); delete player; } } } return true; }
bool IOMapOTBM::loadMap(Map* map, const std::string& identifier) { int64_t start = OTSYS_TIME(); FileLoader f; if(!f.openFile(identifier.c_str(), false, true)){ std::stringstream ss; ss << "Could not open the file " << identifier << "."; setLastErrorString(ss.str()); return false; } unsigned long type; PropStream propStream; NODE root = f.getChildNode((NODE)NULL, type); if(!f.getProps(root, propStream)){ setLastErrorString("Could not read root property."); return false; } OTBM_root_header* root_header; if(!propStream.GET_STRUCT(root_header)){ setLastErrorString("Could not read header."); return false; } if(root_header->version > 2){ setLastErrorString("Unknown OTBM version detected, please update your server.");; return false; } if(root_header->majorVersionItems > (unsigned long)Items::dwMajorVersion){ setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } // Prevent load maps saved with items.otb previous to // version 800, because of the change to stackable of // itemid 3965 if(root_header->minorVersionItems < CLIENT_VERSION_760){ setLastErrorString("This map needs to be updated."); return false; } if(root_header->minorVersionItems > (unsigned long)Items::dwMinorVersion){ std::cout << "Warning: [OTBM loader] This map needs an updated items OTB file." <<std::endl; } std::cout << "Map size: " << root_header->width << "x" << root_header->height << std::endl; map->mapWidth = root_header->width; map->mapHeight = root_header->height; NODE nodeMap = f.getChildNode(root, type); if(type != OTBM_MAP_DATA){ setLastErrorString("Could not read data node."); return false; } if(!f.getProps(nodeMap, propStream)){ setLastErrorString("Could not read map data attributes."); return false; } unsigned char attribute; std::string mapDescription; std::string tmp; while(propStream.GET_UCHAR(attribute)){ switch(attribute){ case OTBM_ATTR_DESCRIPTION: if(!propStream.GET_STRING(mapDescription)){ setLastErrorString("Invalid description tag."); return false; } std::cout << "Map description: " << mapDescription << std::endl; break; case OTBM_ATTR_EXT_SPAWN_FILE: if(!propStream.GET_STRING(tmp)){ setLastErrorString("Invalid spawn tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; case OTBM_ATTR_EXT_HOUSE_FILE: if(!propStream.GET_STRING(tmp)){ setLastErrorString("Invalid house tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; default: setLastErrorString("Unknown header node."); return false; break; } } Tile* tile = NULL; NODE nodeMapData = f.getChildNode(nodeMap, type); while(nodeMapData != NO_NODE){ if(f.getError() != ERROR_NONE){ setLastErrorString("Invalid map node."); return false; } if(type == OTBM_TILE_AREA){ if(!f.getProps(nodeMapData, propStream)){ setLastErrorString("Invalid map node."); return false; } OTBM_Tile_area_coords* area_coord; if(!propStream.GET_STRUCT(area_coord)){ setLastErrorString("Invalid map node."); return false; } int base_x, base_y, base_z; base_x = area_coord->_x; base_y = area_coord->_y; base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while(nodeTile != NO_NODE){ if(f.getError() != ERROR_NONE){ setLastErrorString("Could not read node data."); return false; } if(type == OTBM_TILE || type == OTBM_HOUSETILE){ if(!f.getProps(nodeTile, propStream)){ setLastErrorString("Could not read node data."); return false; } unsigned short px, py, pz; OTBM_Tile_coords* tile_coord; if(!propStream.GET_STRUCT(tile_coord)){ setLastErrorString("Could not read tile position."); return false; } px = base_x + tile_coord->_x; py = base_y + tile_coord->_y; pz = base_z; bool isHouseTile = false; House* house = NULL; if(type == OTBM_TILE){ tile = new Tile(px, py, pz); } else if(type == OTBM_HOUSETILE){ uint32_t _houseid; if(!propStream.GET_ULONG(_houseid)){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().getHouse(_houseid, true); if(!house){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); isHouseTile = true; } //read tile attributes unsigned char attribute; while(propStream.GET_UCHAR(attribute)){ switch(attribute){ case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if(!propStream.GET_ULONG(flags)){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE){ tile->setFlag(TILESTATE_PROTECTIONZONE); } else if((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE){ tile->setFlag(TILESTATE_NOPVPZONE); } else if((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE){ tile->setFlag(TILESTATE_PVPZONE); } if((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT){ tile->setFlag(TILESTATE_NOLOGOUT); } if((flags & TILESTATE_REFRESH) == TILESTATE_REFRESH){ if(house){ std::cout << "Warning [x:" << px << ", y:" << py << ", z:" << pz << "] " << " House tile flagged as refreshing!"; } tile->setFlag(TILESTATE_REFRESH); } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if(!item){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to create item."; setLastErrorString(ss.str()); return false; } if(isHouseTile && !item->isNotMoveable()){ std::cout << "Warning: [OTBM loader] Moveable item in house id = " << house->getHouseId() << " Item type = " << item->getID() << std::endl; delete item; item = NULL; } else{ tile->__internalAddThing(item); item->__startDecaying(); } break; } default: std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Unknown tile attribute."; setLastErrorString(ss.str()); return false; break; } } NODE nodeItem = f.getChildNode(nodeTile, type); while(nodeItem){ if(type == OTBM_ITEM){ PropStream propStream; f.getProps(nodeItem, propStream); Item* item = Item::CreateItem(propStream); if(!item){ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to create item."; setLastErrorString(ss.str()); return false; } if(item->unserializeItemNode(f, nodeItem, propStream)){ if(isHouseTile && !item->isNotMoveable()){ std::cout << "Warning: [OTBM loader] Moveable item in house id = " << house->getHouseId() << " Item type = " << item->getID() << std::endl; delete item; } else{ tile->__internalAddThing(item); item->__startDecaying(); // TESTING if(isHouseTile){ Door* door = item->getDoor(); if(door && door->getDoorId() != 0){ house->addDoor(door); } } // } } else{ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to load item " << item->getID() << "."; setLastErrorString(ss.str()); delete item; return false; } } else{ std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } map->setTile(px, py, pz, tile); } else{ setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if(type == OTBM_TOWNS){ NODE nodeTown = f.getChildNode(nodeMapData, type); while(nodeTown != NO_NODE){ if(type == OTBM_TOWN){ if(!f.getProps(nodeTown, propStream)){ setLastErrorString("Could not read town data."); return false; } uint32_t townid = 0; if(!propStream.GET_ULONG(townid)){ setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townid); if(!town){ town = new Town(townid); Towns::getInstance().addTown(townid, town); } std::string townName = ""; if(!propStream.GET_STRING(townName)){ setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_TownTemple_coords *town_coords; if(!propStream.GET_STRUCT(town_coords)){ setLastErrorString("Could not read town coordinates."); return false; } Position pos; pos.x = town_coords->_x; pos.y = town_coords->_y; pos.z = town_coords->_z; town->setTemplePos(pos); } else{ setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if(type == OTBM_WAYPOINTS && root_header->version >= 2){ NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while(nodeWaypoint != NO_NODE){ if(type == OTBM_WAYPOINT){ if(!f.getProps(nodeWaypoint, propStream)){ setLastErrorString("Could not read town data."); return false; } std::string name; Position pos; if(!propStream.GET_STRING(name)){ setLastErrorString("Could not read waypoint name."); return false; } OTBM_TownTemple_coords* wp_coords; if(!propStream.GET_STRUCT(wp_coords)){ setLastErrorString("Could not read waypoint coordinates."); return false; } pos.x = wp_coords->_x; pos.y = wp_coords->_y; pos.z = wp_coords->_z; Waypoint_ptr wp(new Waypoint(name, pos)); map->waypoints.addWaypoint(wp); } else{ setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else{ setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } std::cout << "Notice: [OTBM Loader] Loading time : " << (OTSYS_TIME() - start)/(1000.) << " s" << std::endl; return true; }
bool IOMap::loadMap(Map* map, const std::string& identifier) { int64_t start = OTSYS_TIME(); FileLoader f; if (!f.openFile(identifier.c_str(), "OTBM", false, true)) { std::ostringstream ss; ss << "Could not open the file " << identifier << "."; setLastErrorString(ss.str()); return false; } uint32_t type; PropStream propStream; NODE root = f.getChildNode((NODE)NULL, type); if (!f.getProps(root, propStream)) { setLastErrorString("Could not read root property."); return false; } OTBM_root_header* root_header; if (!propStream.GET_STRUCT(root_header)) { setLastErrorString("Could not read header."); return false; } uint32_t headerVersion = root_header->version; if (headerVersion <= 0) { //In otbm version 1 the count variable after splashes/fluidcontainers and stackables //are saved as attributes instead, this solves alot of problems with items //that is changed (stackable/charges/fluidcontainer/splash) during an update. setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if (headerVersion > 2) { setLastErrorString("Unknown OTBM version detected."); return false; } if (root_header->majorVersionItems < 3) { setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if (root_header->majorVersionItems > (uint32_t)Items::dwMajorVersion) { setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } if (root_header->minorVersionItems < CLIENT_VERSION_810) { setLastErrorString("This map needs to be updated."); return false; } if (root_header->minorVersionItems > (uint32_t)Items::dwMinorVersion) { std::cout << "Warning: [OTBM loader] This map needs an updated items.otb." << std::endl; } std::cout << "> Map size: " << root_header->width << "x" << root_header->height << "." << std::endl; map->mapWidth = root_header->width; map->mapHeight = root_header->height; NODE nodeMap = f.getChildNode(root, type); if (type != OTBM_MAP_DATA) { setLastErrorString("Could not read data node."); return false; } if (!f.getProps(nodeMap, propStream)) { setLastErrorString("Could not read map data attributes."); return false; } unsigned char attribute; std::string mapDescription; std::string tmp; while (propStream.GET_UCHAR(attribute)) { switch (attribute) { case OTBM_ATTR_DESCRIPTION: if (!propStream.GET_STRING(mapDescription)) { setLastErrorString("Invalid description tag."); return false; } break; case OTBM_ATTR_EXT_SPAWN_FILE: if (!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid spawn tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; case OTBM_ATTR_EXT_HOUSE_FILE: if (!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid house tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; default: setLastErrorString("Unknown header node."); return false; } } NODE nodeMapData = f.getChildNode(nodeMap, type); while (nodeMapData != NO_NODE) { if (f.getError() != ERROR_NONE) { setLastErrorString("Invalid map node."); return false; } if (type == OTBM_TILE_AREA) { if (!f.getProps(nodeMapData, propStream)) { setLastErrorString("Invalid map node."); return false; } OTBM_Destination_coords* area_coord; if (!propStream.GET_STRUCT(area_coord)) { setLastErrorString("Invalid map node."); return false; } int32_t base_x, base_y, base_z; base_x = area_coord->_x; base_y = area_coord->_y; base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while (nodeTile != NO_NODE) { if (f.getError() != ERROR_NONE) { setLastErrorString("Could not read node data."); return false; } if (type == OTBM_TILE || type == OTBM_HOUSETILE) { if (!f.getProps(nodeTile, propStream)) { setLastErrorString("Could not read node data."); return false; } unsigned short px, py, pz; OTBM_Tile_coords* tile_coord; if (!propStream.GET_STRUCT(tile_coord)) { setLastErrorString("Could not read tile position."); return false; } px = base_x + tile_coord->_x; py = base_y + tile_coord->_y; pz = base_z; bool isHouseTile = false; House* house = NULL; Tile* tile = NULL; Item* ground_item = NULL; uint32_t tileflags = TILESTATE_NONE; if (type == OTBM_HOUSETILE) { uint32_t _houseid; if (!propStream.GET_ULONG(_houseid)) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().getHouse(_houseid, true); if (!house) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); isHouseTile = true; } //read tile attributes while (propStream.GET_UCHAR(attribute)) { switch (attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if (!propStream.GET_ULONG(flags)) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if ((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) { tileflags |= TILESTATE_PROTECTIONZONE; } else if ((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE) { tileflags |= TILESTATE_NOPVPZONE; } else if ((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE) { tileflags |= TILESTATE_PVPZONE; } if ((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) { tileflags |= TILESTATE_NOLOGOUT; } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if (!item) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to create item."; setLastErrorString(ss.str()); return false; } if (isHouseTile && !item->isNotMoveable()) { std::cout << "Warning: [OTBM loader] Moveable item with ID: " << item->getID() << ", in house: " << house->getHouseId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl; delete item; item = NULL; } else { if (item->getItemCount() <= 0) { item->setItemCount(1); } if (tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if (item->isGroundTile()) { delete ground_item; ground_item = item; } else { tile = createTile(ground_item, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } break; } default: std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Unknown tile attribute."; setLastErrorString(ss.str()); return false; } } NODE nodeItem = f.getChildNode(nodeTile, type); while (nodeItem) { if (type == OTBM_ITEM) { PropStream stream; f.getProps(nodeItem, stream); Item* item = Item::CreateItem(stream); if (!item) { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to create item."; setLastErrorString(ss.str()); return false; } if (item->unserializeItemNode(f, nodeItem, stream)) { if (isHouseTile && !item->isNotMoveable()) { std::cout << "Warning: [OTBM loader] Moveable item with ID: " << item->getID() << ", in house: " << house->getHouseId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl; delete item; } else { if (item->getItemCount() <= 0) { item->setItemCount(1); } if (tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if (item->isGroundTile()) { delete ground_item; ground_item = item; } else { tile = createTile(ground_item, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } } else { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Failed to load item " << item->getID() << "."; setLastErrorString(ss.str()); delete item; return false; } } else { std::ostringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] " << "Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } if (!tile) { tile = createTile(ground_item, NULL, px, py, pz); } tile->setFlag((tileflags_t)tileflags); map->setTile(px, py, pz, tile); } else { setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if (type == OTBM_TOWNS) { NODE nodeTown = f.getChildNode(nodeMapData, type); while (nodeTown != NO_NODE) { if (type == OTBM_TOWN) { if (!f.getProps(nodeTown, propStream)) { setLastErrorString("Could not read town data."); return false; } uint32_t townid = 0; if (!propStream.GET_ULONG(townid)) { setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townid); if (!town) { town = new Town(townid); Towns::getInstance().addTown(townid, town); } std::string townName; if (!propStream.GET_STRING(townName)) { setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_Destination_coords* town_coords; if (!propStream.GET_STRUCT(town_coords)) { setLastErrorString("Could not read town coordinates."); return false; } Position pos; pos.x = town_coords->_x; pos.y = town_coords->_y; pos.z = town_coords->_z; town->setTemplePos(pos); } else { setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if (type == OTBM_WAYPOINTS && headerVersion > 1) { NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while (nodeWaypoint != NO_NODE) { if (type == OTBM_WAYPOINT) { if (!f.getProps(nodeWaypoint, propStream)) { setLastErrorString("Could not read waypoint data."); return false; } std::string name; if (!propStream.GET_STRING(name)) { setLastErrorString("Could not read waypoint name."); return false; } OTBM_Destination_coords* waypoint_coords; if (!propStream.GET_STRUCT(waypoint_coords)) { setLastErrorString("Could not read waypoint coordinates."); return false; } map->waypoints[name] = Position(waypoint_coords->_x, waypoint_coords->_y, waypoint_coords->_z); } else { setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else { setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } std::cout << "> Map loading time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; return true; }
bool IOMapSerialize::saveHouseInfo(Map* map) { Database* db = Database::getInstance(); DBTransaction transaction; if (!transaction.begin()) { return false; } if (!db->executeQuery("DELETE FROM `house_lists`")) { return false; } std::ostringstream query; for (const auto& it : Houses::getInstance().getHouses()) { House* house = it.second; query << "SELECT `id` FROM `houses` WHERE `id` = " << house->getHouseId(); DBResult* result = db->storeQuery(query.str()); if (result) { db->freeResult(result); query.str(""); query << "UPDATE `houses` SET `owner` = " << house->getHouseOwner() << ", `paid` = " << house->getPaidUntil() << ", `warnings` = " << house->getPayRentWarnings() << ", `name` = " << db->escapeString(house->getName()) << ", `town_id` = " << house->getTownId() << ", `rent` = " << house->getRent() << ", `size` = " << house->getHouseTiles().size() << ", `beds` = " << house->getBedCount() << " WHERE `id` = " << house->getHouseId(); } else { query.str(""); query << "INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`) VALUES (" << house->getHouseId() << "," << house->getHouseOwner() << "," << house->getPaidUntil() << "," << house->getPayRentWarnings() << "," << db->escapeString(house->getName()) << "," << house->getTownId() << "," << house->getRent() << "," << house->getHouseTiles().size() << "," << house->getBedCount() << ")"; } db->executeQuery(query.str()); query.str(""); } DBInsert stmt; stmt.setQuery("INSERT INTO `house_lists` (`house_id` , `listid` , `list`) VALUES "); for (const auto& it : Houses::getInstance().getHouses()) { House* house = it.second; std::string listText; if (house->getAccessList(GUEST_LIST, listText) && listText != "") { query << house->getHouseId() << "," << GUEST_LIST << "," << db->escapeString(listText); if (!stmt.addRow(query)) { return false; } } if (house->getAccessList(SUBOWNER_LIST, listText) && listText != "") { query << house->getHouseId() << "," << SUBOWNER_LIST << "," << db->escapeString(listText); if (!stmt.addRow(query)) { return false; } } for (Door* door : house->getHouseDoors()) { if (door->getAccessList(listText) && listText != "") { query << house->getHouseId() << "," << door->getDoorId() << "," << db->escapeString(listText); if (!stmt.addRow(query)) { return false; } } } } if (!stmt.execute()) { return false; } return transaction.commit(); }