Пример #1
0
Attr_ReadValue Teleport::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	if(ATTR_TELE_DEST == attr){
		TeleportDest tele_dest;
		if(		!propStream.GET_UINT16(tele_dest._x) ||
				!propStream.GET_UINT16(tele_dest._y) ||
				!propStream.GET_UINT8(tele_dest._z))
		{
			return ATTR_READ_ERROR;
		}

		setDestPos(Position(tele_dest._x, tele_dest._y, tele_dest._z));
		return ATTR_READ_CONTINUE;
	}
	else
		return Item::readAttr(attr, propStream);
}
Пример #2
0
bool IOMapOTBM::loadMap(Map* map, const std::string& identifier)
{
	int64_t start = OTSYS_TIME();

	FileLoader f;
	if(!f.openFile(identifier.c_str(), "OTBM", 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_UINT32(root_header.version) ||
			!propStream.GET_UINT16(root_header.width) ||
			!propStream.GET_UINT16(root_header.height) ||
			!propStream.GET_UINT32(root_header.majorVersionItems) ||
			!propStream.GET_UINT32(root_header.minorVersionItems))
	{
		setLastErrorString("Could not read header.");
		return false;
	}

	int header_version = root_header.version;
	if(header_version <= 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(header_version > 2){
		setLastErrorString("Unknown OTBM version detected, please update your server.");
		return false;
	}

	if(root_header.majorVersionItems < 3){
		setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly.");
		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_810){
		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." <<std::endl;
	}
	if(root_header.minorVersionItems == CLIENT_VERSION_854_BAD){
		std::cout << "Warning: [OTBM loader] This map needs uses an incorrect version of 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_UINT8(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;
		}
	}

	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_UINT16(area_coord._x) ||
					!propStream.GET_UINT16(area_coord._y) ||
					!propStream.GET_UINT8(area_coord._z))
			{
				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_UINT8(tile_coord._x) ||
							!propStream.GET_UINT8(tile_coord._y))
					{
						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_UINT32(_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_UINT8(attribute)){
						switch(attribute){
						case OTBM_ATTR_TILE_FLAGS:
						{
							uint32_t flags;
							if(!propStream.GET_UINT32(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 << "Warning [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(isHouseTile && !item->isNotMoveable()){
								std::cout << "Warning: [OTBM loader] Moveable item in house id = " << house->getId() << " Item type = " << item->getID() << std::endl;
								delete item;
								item = NULL;
							}
							else{
								if(tile){
									tile->__internalAddThing(item);
									item->__startDecaying();
								}
								else if(item->isGroundTile()){
									if(ground_item)
										delete ground_item;
									ground_item = item;
								}
								else{ // !tile
									tile = createTile(ground_item, item, px, py, pz);
									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->getId() << " Item type = " << item->getID() << std::endl;
									delete item;
								}
								else{
									if(tile){
										tile->__internalAddThing(item);
										item->__startDecaying();
									}
									else if(item->isGroundTile()){
										if(ground_item)
											delete ground_item;
										ground_item = item;
									}
									else{ // !tile
										tile = createTile(ground_item, item, px, py, pz);
										tile->__internalAddThing(item);
										item->__startDecaying();
									}
								}
							}
							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);
					}

					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_UINT32(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_UINT16(town_coords._x) ||
							!propStream.GET_UINT16(town_coords._y) ||
							!propStream.GET_UINT8(town_coords._z))
					{
						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 && 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 waypoint 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_UINT16(wp_coords._x) ||
							!propStream.GET_UINT16(wp_coords._y) ||
							!propStream.GET_UINT8(wp_coords._z))
					{
						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;
}
Пример #3
0
Attr_ReadValue Item::readAttr(const AttrTypes_t& attr, PropStream& propStream)
{
	switch (attr)
	{
		case ATTR_COUNT:
		{
			uint8_t _count = 0;

			if (!propStream.GET_UINT8(_count))
			{
				return ATTR_READ_ERROR;
			}

			setSubType(_count);
			break;
		}
		case ATTR_ACTION_ID:
		{
			uint16_t _actionid = 0;

			if (!propStream.GET_UINT16(_actionid))
			{
				return ATTR_READ_ERROR;
			}

			setActionId(_actionid);
			break;
		}
		case ATTR_UNIQUE_ID:
		{
			uint16_t _uniqueid;

			if (!propStream.GET_UINT16(_uniqueid))
			{
				return ATTR_READ_ERROR;
			}

			setUniqueId(_uniqueid);
			break;
		}
		case ATTR_TEXT:
		{
			std::string _text;

			if (!propStream.GET_STRING(_text))
			{
				return ATTR_READ_ERROR;
			}

			setText(_text);
			break;
		}
		case ATTR_WRITTENDATE:
		{
			uint32_t _writtenDate;

			if (!propStream.GET_UINT32(_writtenDate))
			{
				return ATTR_READ_ERROR;
			}

			setWrittenDate(_writtenDate);
			break;
		}
		case ATTR_WRITTENBY:
		{
			std::string _writer;

			if (!propStream.GET_STRING(_writer))
			{
				return ATTR_READ_ERROR;
			}

			setWriter(_writer);
			break;
		}
		case ATTR_DESC:
		{
			std::string _text;

			if (!propStream.GET_STRING(_text))
			{
				return ATTR_READ_ERROR;
			}

			setSpecialDescription(_text);
			break;
		}
		case ATTR_RUNE_CHARGES:
		{
			uint8_t _charges = 1;

			if (!propStream.GET_UINT8(_charges))
			{
				return ATTR_READ_ERROR;
			}

			setSubType(_charges);
			break;
		}
		case ATTR_CHARGES:
		{
			uint16_t _charges = 1;

			if (!propStream.GET_UINT16(_charges))
			{
				return ATTR_READ_ERROR;
			}

			setSubType(_charges);
			break;
		}
		case ATTR_DURATION:
		{
			uint32_t duration = 0;

			if (!propStream.GET_UINT32(duration))
			{
				return ATTR_READ_ERROR;
			}

			if (((int32_t)duration) < 0)
			{
				duration = 0;
			}

			setDuration(duration);
			break;
		}
		case ATTR_DECAYING_STATE:
		{
			uint8_t state = 0;

			if (!propStream.GET_UINT8(state))
			{
				return ATTR_READ_ERROR;
			}

			if (state != DECAYING_FALSE)
			{
				setDecaying(DECAYING_PENDING);
			}

			break;
		}
		//these should be handled through derived classes
		//If these are called then something has changed in the items.xml since the map was saved
		//just read the values
		//Depot class
		case ATTR_DEPOT_ID:
		{
			uint16_t _depotId;

			if (!propStream.GET_UINT16(_depotId))
			{
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}
		//Door class
		case ATTR_HOUSEDOORID:
		{
			uint8_t _doorId;

			if (!propStream.GET_UINT8(_doorId))
			{
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}
		//Bed class
		case ATTR_SLEEPERGUID:
		{
			uint32_t _guid;

			if (!propStream.GET_UINT32(_guid))
			{
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}
		case ATTR_SLEEPSTART:
		{
			uint32_t sleep_start;

			if (!propStream.GET_UINT32(sleep_start))
			{
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}
		//Teleport class
		case ATTR_TELE_DEST:
		{
			TeleportDest tele_dest;

			if (!propStream.GET_UINT16(tele_dest._x) ||
			        !propStream.GET_UINT16(tele_dest._y) ||
			        !propStream.GET_UINT8(tele_dest._z))
			{
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}
		//Container class
		case ATTR_CONTAINER_ITEMS:
		{
			uint32_t count;

			if (!propStream.GET_UINT32(count))
			{
				return ATTR_READ_ERROR;
			}

			//We cant continue parse attributes since there is
			//container data after this attribute.
			return ATTR_READ_ERROR;
		}
		default:
			return ATTR_READ_ERROR;
			break;
	}

	return ATTR_READ_CONTINUE;
}