void ThingTypeOtb::unserialize(const BinaryTreePtr& node) { m_null = false; m_category = (OtbCategory)node->getU8(); node->getU32(); // flags while(node->canRead()) { uint8 attr = node->getU8(); if(attr == 0 || attr == 0xFF) break; uint16 len = node->getU16(); switch(attr) { case OtbAttribServerId: m_serverId = node->getU16(); assert(len == 2); break; case OtbAttribClientId: m_clientId = node->getU16(); assert(len == 2); break; default: node->skip(len); // skip attribute break; } } }
void ItemType::unserialize(const BinaryTreePtr& node) { m_null = false; m_category = (ItemCategory)node->getU8(); node->getU32(); // flags static uint16 lastId = 99; while(node->canRead()) { uint8 attr = node->getU8(); if(attr == 0 || attr == 0xFF) break; uint16 len = node->getU16(); switch(attr) { case ItemTypeAttrServerId: { uint16 serverId = node->getU16(); if(g_game.getClientVersion() < 960) { if(serverId > 20000 && serverId < 20100) { serverId -= 20000; } else if(lastId > 99 && lastId != serverId - 1) { while(lastId != serverId - 1) { ItemTypePtr tmp(new ItemType); tmp->setServerId(lastId++); g_things.addItemType(tmp); } } } else { if(serverId > 30000 && serverId < 30100) { serverId -= 30000; } else if(lastId > 99 && lastId != serverId - 1) { while(lastId != serverId - 1) { ItemTypePtr tmp(new ItemType); tmp->setServerId(lastId++); g_things.addItemType(tmp); } } } setServerId(serverId); lastId = serverId; break; } case ItemTypeAttrClientId: setClientId(node->getU16()); break; case ItemTypeAttrName: setName(node->getString(len)); break; case ItemTypeAttrWritable: m_attribs.set(ItemTypeAttrWritable, true); break; default: node->skip(len); // skip attribute break; } } }
void ThingTypeManager::loadOtb(const std::string& file) { try { FileStreamPtr fin = g_resources.openFile(file); uint signature = fin->getU32(); if(signature != 0) stdext::throw_exception("invalid otb file"); BinaryTreePtr root = fin->getBinaryTree(); root->skip(1); // otb first byte is always 0 signature = root->getU32(); if(signature != 0) stdext::throw_exception("invalid otb file"); uint8 rootAttr = root->getU8(); if(rootAttr == 0x01) { // OTB_ROOT_ATTR_VERSION uint16 size = root->getU16(); if(size != 4 + 4 + 4 + 128) stdext::throw_exception("invalid otb root attr version size"); m_otbMajorVersion = root->getU32(); m_otbMinorVersion = root->getU32(); root->skip(4); // buildNumber root->skip(128); // description } m_reverseItemTypes.clear(); m_itemTypes.resize(root->getChildren().size() + 1, m_nullItemType); m_reverseItemTypes.resize(root->getChildren().size() + 1, m_nullItemType); for(const BinaryTreePtr& node : root->getChildren()) { ItemTypePtr itemType(new ItemType); itemType->unserialize(node); addItemType(itemType); uint16 clientId = itemType->getClientId(); if(unlikely(clientId >= m_reverseItemTypes.size())) m_reverseItemTypes.resize(clientId + 1); m_reverseItemTypes[clientId] = itemType; } m_otbLoaded = true; g_lua.callGlobalField("g_things", "onLoadOtb", file); } catch(std::exception& e) { g_logger.error(stdext::format("Failed to load '%s' (OTB file): %s", file, e.what())); } }
void Map::loadOtbm(const std::string& fileName) { FileStreamPtr fin = g_resources.openFile(fileName); if(!fin) stdext::throw_exception(stdext::format("Unable to load map '%s'", fileName)); fin->cache(); if(!g_things.isOtbLoaded()) stdext::throw_exception("OTB isn't loaded yet to load a map."); if(fin->getU32()) stdext::throw_exception("Unknown file version detected"); BinaryTreePtr root = fin->getBinaryTree(); if(root->getU8()) stdext::throw_exception("could not read root property!"); uint32 headerVersion = root->getU32(); if(!headerVersion || headerVersion > 3) stdext::throw_exception(stdext::format("Unknown OTBM version detected: %u.", headerVersion)); setWidth(root->getU16()); setHeight(root->getU16()); uint32 headerMajorItems = root->getU8(); if(headerMajorItems < 3) { stdext::throw_exception(stdext::format("This map needs to be upgraded. read %d what it's supposed to be: %u", headerMajorItems, g_things.getOtbMajorVersion())); } if(headerMajorItems > g_things.getOtbMajorVersion()) { stdext::throw_exception(stdext::format("This map was saved with different OTB version. read %d what it's supposed to be: %d", headerMajorItems, g_things.getOtbMajorVersion())); } root->skip(3); uint32 headerMinorItems = root->getU32(); if(headerMinorItems > g_things.getOtbMinorVersion()) { g_logger.warning(stdext::format("This map needs an updated OTB. read %d what it's supposed to be: %d or less", headerMinorItems, g_things.getOtbMinorVersion())); } BinaryTreePtr node = root->getChildren()[0]; if(node->getU8() != OTBM_MAP_DATA) stdext::throw_exception("Could not read root data node"); while (node->canRead()) { uint8 attribute = node->getU8(); std::string tmp = node->getString(); switch (attribute) { case OTBM_ATTR_DESCRIPTION: setDescription(tmp); break; case OTBM_ATTR_SPAWN_FILE: setSpawnFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); break; case OTBM_ATTR_HOUSE_FILE: setHouseFile(fileName.substr(0, fileName.rfind('/') + 1) + tmp); break; default: stdext::throw_exception(stdext::format("Invalid attribute '%d'", (int)attribute)); } } for(const BinaryTreePtr &nodeMapData : node->getChildren()) { uint8 mapDataType = nodeMapData->getU8(); if(mapDataType == OTBM_TILE_AREA) { Position basePos = nodeMapData->getPosition(); for(const BinaryTreePtr &nodeTile : nodeMapData->getChildren()) { uint8 type = nodeTile->getU8(); if(type != OTBM_TILE && type != OTBM_HOUSETILE) stdext::throw_exception(stdext::format("invalid node tile type %d", (int)type)); HousePtr house = nullptr; uint32 flags = TILESTATE_NONE; Position pos = basePos + nodeTile->getPoint(); if(type == OTBM_HOUSETILE) { uint32 hId = nodeTile->getU32(); TilePtr tile = getOrCreateTile(pos); if(!(house = m_houses.getHouse(hId))) { house = HousePtr(new House(hId)); m_houses.addHouse(house); } house->setTile(tile); } while(nodeTile->canRead()) { uint8 tileAttr = nodeTile->getU8(); switch (tileAttr) { case OTBM_ATTR_TILE_FLAGS: { uint32 _flags = nodeTile->getU32(); if((_flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) flags |= TILESTATE_PROTECTIONZONE; else if((_flags & TILESTATE_OPTIONALZONE) == TILESTATE_OPTIONALZONE) flags |= TILESTATE_OPTIONALZONE; else if((_flags & TILESTATE_HARDCOREZONE) == TILESTATE_HARDCOREZONE) flags |= TILESTATE_HARDCOREZONE; if((_flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) flags |= TILESTATE_NOLOGOUT; if((_flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) flags |= TILESTATE_REFRESH; break; } case OTBM_ATTR_ITEM: { addThing(Item::createFromOtb(nodeTile->getU16()), pos); break; } default: { stdext::throw_exception(stdext::format("invalid tile attribute %d at pos %s", (int)tileAttr, stdext::to_string(pos))); } } } for(const BinaryTreePtr &nodeItem : nodeTile->getChildren()) { if(nodeItem->getU8() != OTBM_ITEM) stdext::throw_exception("invalid item node"); ItemPtr item = Item::createFromOtb(nodeItem->getU16()); item->unserializeItem(nodeItem); if(item->isContainer()) { for(const BinaryTreePtr& containerItem : nodeItem->getChildren()) { if(containerItem->getU8() != OTBM_ITEM) stdext::throw_exception("invalid container item node"); ItemPtr cItem = Item::createFromOtb(containerItem->getU16()); cItem->unserializeItem(containerItem); //item->addContainerItem(cItem); } } if(house && item->isMoveable()) { g_logger.warning(stdext::format("Movable item found in house: %d at pos %s - escaping...", item->getId(), stdext::to_string(pos))); item.reset(); } addThing(item, pos); } if(const TilePtr& tile = getTile(pos)) tile->setFlags((tileflags_t)flags); } } else if(mapDataType == OTBM_TOWNS) { TownPtr town = nullptr; for(const BinaryTreePtr &nodeTown : nodeMapData->getChildren()) { if(nodeTown->getU8() != OTBM_TOWN) stdext::throw_exception("invalid town node."); uint32 townId = nodeTown->getU32(); std::string townName = nodeTown->getString(); Position townCoords = nodeTown->getPosition(); if(!(town = m_towns.getTown(townId))) { town = TownPtr(new Town(townId, townName, townCoords)); m_towns.addTown(town); } } } else if(mapDataType == OTBM_WAYPOINTS && headerVersion > 1) { for(const BinaryTreePtr &nodeWaypoint : nodeMapData->getChildren()) { if(nodeWaypoint->getU8() != OTBM_WAYPOINT) stdext::throw_exception("invalid waypoint node."); std::string name = nodeWaypoint->getString(); Position waypointPos = nodeWaypoint->getPosition(); if(waypointPos.isValid() && !name.empty() && m_waypoints.find(waypointPos) == m_waypoints.end()) m_waypoints.insert(std::make_pair(waypointPos, name)); } } else stdext::throw_exception(stdext::format("Unknown map data node %d", (int)mapDataType)); } g_logger.debug("OTBM read successfully."); fin->close(); loadSpawns(getSpawnFile()); // m_houses.load(getHouseFile()); }
void Item::unserializeItem(const BinaryTreePtr &in) { try { while(in->canRead()) { int attrib = in->getU8(); if(attrib == 0) break; switch(attrib) { case ATTR_COUNT: case ATTR_RUNE_CHARGES: setCount(in->getU8()); break; case ATTR_CHARGES: setCount(in->getU16()); break; case ATTR_HOUSEDOORID: case ATTR_SCRIPTPROTECTED: case ATTR_DUALWIELD: case ATTR_DECAYING_STATE: m_attribs.set(attrib, in->getU8()); break; case ATTR_ACTION_ID: case ATTR_UNIQUE_ID: case ATTR_DEPOT_ID: m_attribs.set(attrib, in->getU16()); break; case ATTR_CONTAINER_ITEMS: case ATTR_ATTACK: case ATTR_EXTRAATTACK: case ATTR_DEFENSE: case ATTR_EXTRADEFENSE: case ATTR_ARMOR: case ATTR_ATTACKSPEED: case ATTR_HITCHANCE: case ATTR_DURATION: case ATTR_WRITTENDATE: case ATTR_SLEEPERGUID: case ATTR_SLEEPSTART: case ATTR_ATTRIBUTE_MAP: m_attribs.set(attrib, in->getU32()); break; case ATTR_TELE_DEST: { Position pos; pos.x = in->getU16(); pos.y = in->getU16(); pos.z = in->getU8(); m_attribs.set(attrib, pos); break; } case ATTR_NAME: case ATTR_TEXT: case ATTR_DESC: case ATTR_ARTICLE: case ATTR_WRITTENBY: m_attribs.set(attrib, in->getString()); break; default: stdext::throw_exception(stdext::format("invalid item attribute %d", attrib)); } } } catch(stdext::exception& e) { g_logger.error(stdext::format("Failed to unserialize OTBM item: %s", e.what())); } }