Пример #1
0
bool ItemAttribute::unserialize(PropStream& stream)
{
  // dealloc possible string value
  dealloc();
  
  // read type
  stream.GET_UCHAR(reinterpret_cast<uint8_t&>(m_type));
  
  // do not call here set(...) or any other function depending on m_type which may result in deallocating phantom string !

  // read contents
  switch(m_type){
    case STRING: {
      m_var.string = new std::string;   
      if(!stream.GET_LSTRING(*m_var.string))
        return false;
      
      break;
    }
    
    case INTEGER: 
    case FLOAT: {
      if(!stream.GET_ULONG(m_var.unsignedInteger))
        return false;
      
      break;
    }
    
    case BOOLEAN: {
      if(!stream.GET_UCHAR(m_var.unsignedChar))
        return false;
        
      break;
    }
    
    default: {
      m_type = NONE; 
      break;
    }
  }
  
  return true;
}
Пример #2
0
bool Condition::unserialize(PropStream& propStream)
{
	uint8_t attr_type;
	while(propStream.GET_UCHAR(attr_type) && attr_type != CONDITIONATTR_END)
	{
		if(!unserializeProp((ConditionAttr_t)attr_type, propStream))
			return false;
	}
	return true;
}
Пример #3
0
bool IOMapSerialize::loadMap(Map* map)
{
	int64_t start = OTSYS_TIME();

	Database* db = Database::getInstance();
	std::ostringstream query;

	DBResult* result = db->storeQuery("SELECT `id` FROM `houses`");
	if (!result) {
		return true;
	}

	do {
		query.str("");
		query << "SELECT `data` FROM `tile_store` WHERE `house_id` = " << result->getDataInt("id");
		DBResult* tileResult = db->storeQuery(query.str());
		if (!tileResult) {
			continue;
		}

		do {
			unsigned long attrSize = 0;
			const char* attr = tileResult->getDataStream("data", attrSize);

			PropStream propStream;
			propStream.init(attr, attrSize);

			uint16_t x = 0, y = 0;
			uint8_t z = 0;
			propStream.GET_USHORT(x);
			propStream.GET_USHORT(y);
			propStream.GET_UCHAR(z);
			if (x == 0 || y == 0) {
				continue;
			}

			Tile* tile = map->getTile(x, y, z);
			if (!tile) {
				continue;
			}

			uint32_t item_count = 0;
			propStream.GET_ULONG(item_count);

			while (item_count--) {
				loadItem(propStream, tile);
			}
		} while (tileResult->next());
		db->freeResult(tileResult);
	} while (result->next());
	db->freeResult(result);
	std::cout << "> Loaded house items in: " << (OTSYS_TIME() - start) / (1000.) << " s" << std::endl;
	return true;
}
Пример #4
0
Attr_ReadValue Teleport::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	if (ATTR_TELE_DEST == attr) {
		if (!propStream.GET_USHORT(destPos.x) || !propStream.GET_USHORT(destPos.y) || !propStream.GET_UCHAR(destPos.z)) {
			return ATTR_READ_ERROR;
		}
		return ATTR_READ_CONTINUE;
	} else {
		return Item::readAttr(attr, propStream);
	}
}
Пример #5
0
Attr_ReadValue Door::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	if(attr != ATTR_HOUSEDOORID)
		return Item::readAttr(attr, propStream);

	uint8_t doorId = 0;
	if(!propStream.GET_UCHAR(doorId))
		return ATTR_READ_ERROR;

	setDoorId(doorId);
	return ATTR_READ_CONTINUE;
}
Пример #6
0
bool Item::unserializeAttr(PropStream& propStream)
{
	unsigned char attr_type;
	while(propStream.GET_UCHAR(attr_type)){
		if(!readAttr((AttrTypes_t)attr_type, propStream)){
			return false;
			break;
		}
	}

	return true;
}
Пример #7
0
Attr_ReadValue Door::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	if (ATTR_HOUSEDOORID == attr) {
		unsigned char _doorId = 0;
		if (!propStream.GET_UCHAR(_doorId)) {
			return ATTR_READ_ERROR;
		}

		setDoorId(_doorId);
		return ATTR_READ_CONTINUE;
	} else {
		return Item::readAttr(attr, propStream);
	}
}
Пример #8
0
bool Door::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	if(ATTR_HOUSEDOORID == attr){
		unsigned char _doorId = 0;
		if(!propStream.GET_UCHAR(_doorId)){
			return false;
		}

		setDoorId(_doorId);
		return true;
	}
	else
		return Item::readAttr(attr, propStream);
}
Пример #9
0
bool Item::unserializeAttr(PropStream& propStream)
{
	uint8_t attr_type;

	while (propStream.GET_UCHAR(attr_type) && attr_type != 0) {
		Attr_ReadValue ret = readAttr((AttrTypes_t)attr_type, propStream);

		if (ret == ATTR_READ_ERROR) {
			return false;
		} else if (ret == ATTR_READ_END) {
			return true;
		}
	}

	return true;
}
Пример #10
0
bool IOMapSerialize::loadContainer(PropStream& propStream, Container* container)
{
	while (container->serializationCount > 0) {
		if (!loadItem(propStream, container)) {
			std::cout << "[Warning - IOMapSerialize::loadContainer] Unserialization error for container item: " << container->getID() << std::endl;
			return false;
		}
		container->serializationCount--;
	}

	uint8_t endAttr;
	if (!propStream.GET_UCHAR(endAttr) || endAttr != 0) {
		std::cout << "[Warning - IOMapSerialize::loadContainer] Unserialization error for container item: " << container->getID() << std::endl;
		return false;
	}
	return true;
}
Пример #11
0
bool IOMapSerialize::loadContainer(PropStream& propStream, Container* container)
{
	while (container->serializationCount > 0) {
		if (!loadItem(propStream, container)) {
			std::cout << "WARNING: Unserialization error for containing item in IOMapSerialize::loadContainer() - " << container->getID() << std::endl;
			return false;
		}
		container->serializationCount--;
	}

	uint8_t endAttr = 0;
	propStream.GET_UCHAR(endAttr);
	if (endAttr != 0x00) {
		std::cout << "WARNING: Unserialization error for containing item in IOMapSerialize::loadContainer() - " << container->getID() << std::endl;
		return false;
	}
	return true;
}
Пример #12
0
void IOMapSerialize::loadMap(Map* map)
{
	int64_t start = OTSYS_TIME();

	Database* db = Database::getInstance();

	DBResult* result = db->storeQuery("SELECT `data` FROM `tile_store`");
	if (!result) {
		return;
	}

	do {
		unsigned long attrSize;
		const char* attr = result->getDataStream("data", attrSize);

		PropStream propStream;
		propStream.init(attr, attrSize);

		uint16_t x, y;
		uint8_t z;
		if (!propStream.GET_USHORT(x) || !propStream.GET_USHORT(y) || !propStream.GET_UCHAR(z)) {
			continue;
		}

		Tile* tile = map->getTile(x, y, z);
		if (!tile) {
			continue;
		}

		uint32_t item_count;
		if (!propStream.GET_ULONG(item_count)) {
			continue;
		}

		while (item_count--) {
			loadItem(propStream, tile);
		}
	} while (result->next());
	db->freeResult(result);
	std::cout << "> Loaded house items in: " << (OTSYS_TIME() - start) / (1000.) << " s" << std::endl;
}
Пример #13
0
bool IOMapSerialize::loadContainer(PropStream& propStream, Container* container)
{
	while(container->serializationCount > 0)
	{
		if(!loadItem(propStream, container, false))
		{
			std::cout << "[Warning - IOMapSerialize::loadContainer] Unserialization error [0] for item in container " << container->getID() << std::endl;
			return false;
		}

		container->serializationCount--;
	}

	uint8_t endAttr = ATTR_END;
	propStream.GET_UCHAR(endAttr);
	if(endAttr == ATTR_END)
		return true;

	std::cout << "[Warning - IOMapSerialize::loadContainer] Unserialization error [1] for item in container " << container->getID() << std::endl;
	return false;
}
Пример #14
0
bool Item::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	switch(attr){
		case ATTR_COUNT:
		{
			unsigned char _count = 0;
			if(!propStream.GET_UCHAR(_count)){
				return false;
			}

			setItemCountOrSubtype(_count);
			break;
		}

		case ATTR_ACTION_ID:
		{
			unsigned short _actionid = 0;
			if(!propStream.GET_USHORT(_actionid)){
				return false;
			}

			setActionId(_actionid);
			break;
		}

		case ATTR_UNIQUE_ID:
		{
			unsigned short _uniqueid;
			if(!propStream.GET_USHORT(_uniqueid)){
				return false;
			}
			
			setUniqueId(_uniqueid);
			break;
		}

		case ATTR_TEXT:
		{
			std::string _text;
			if(!propStream.GET_STRING(_text)){
				return false;
			}

			setText(_text);
			break;
		}

		case ATTR_DESC:
		{
			std::string _text;
			if(!propStream.GET_STRING(_text)){
				return false;
			}

			setSpecialDescription(_text);
			break;
		}

		case ATTR_RUNE_CHARGES:
		{
			unsigned char _charges = 1;
			if(!propStream.GET_UCHAR(_charges)){
				return false;
			}

			setItemCountOrSubtype(_charges);
			break;
		}

		//these should be handled through derived classes
		//If these are called then something has changed in the items.otb since the map was saved
		//just read the values

		//Depot class
		case ATTR_DEPOT_ID:
		{
			unsigned short _depotId;
			if(!propStream.GET_USHORT(_depotId)){
				return false;
			}
			
			return true;
		}

		//Door class
		case ATTR_HOUSEDOORID:
		{
			unsigned char _doorId;
			if(!propStream.GET_UCHAR(_doorId)){
				return false;
			}
			
			return true;
		}
	
		//Teleport class
		case ATTR_TELE_DEST:
		{
			TeleportDest* tele_dest;
			if(!propStream.GET_STRUCT(tele_dest)){
				return false;
			}

			return true;
		}

		default:
			return false;
		break;
	}

	return true;
}
Пример #15
0
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;
}
Пример #16
0
bool Condition::unserialize(PropStream& propStream)
{
	uint8_t attr_type;
	while(propStream.GET_UCHAR(attr_type) && attr_type != CONDITIONATTR_END.value()){

		if(attr_type == enums::CONDITIONATTRIBUTE_MECHANIC){
			int32_t value = 0;
			if(!propStream.GET_VALUE(value)){
				return false;
			}

			mechanicType = (MechanicType)value;
		}
		else if(attr_type == enums::CONDITIONATTRIBUTE_COMBAT){
			int32_t value = 0;
			if(!propStream.GET_VALUE(value)){
				return false;
			}

			combatType = (CombatType)value;
			return true;
		}
		else if(attr_type == enums::CONDITIONATTRIBUTE_TICKS){
			uint32_t value = 0;
			if(!propStream.GET_VALUE(value)){
				return false;
			}

			ticks = value;
		}
		else if(attr_type == enums::CONDITIONATTRIBUTE_NAME){
			std::string value;
			if(!propStream.GET_STRING(value)){
				return false;
			}

			name = value;
		}
		else if(attr_type == enums::CONDITIONATTRIBUTE_FLAGS){
			uint32_t value = 0;
			if(!propStream.GET_VALUE(value)){
				return false;
			}

			flags = value;
		}
		else if(attr_type == enums::CONDITIONATTRIBUTE_EFFECT){
			ConditionEffect effect;
			if(!effect.unserialize(propStream)){
				return false;
			}

			addEffect(effect);
		}
		else{
			return false;
		}
	}

	return true;
}
Пример #17
0
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;
}
Пример #18
0
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)nullptr, 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 - IOMap::loadMap] 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 = nullptr;
					Tile* tile = nullptr;
					Item* ground_item = nullptr;
					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().addHouse(_houseid);
						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 - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl;
									delete item;
									item = nullptr;
								} 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 - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", 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, nullptr, 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;
}
Пример #19
0
int32_t Items::loadFromOtb(const std::string& file)
{
	FileLoader f;
	if (!f.openFile(file.c_str(), "OTBI")) {
		return f.getError();
	}

	uint32_t type;
	NODE node = f.getChildNode(NO_NODE, type);

	PropStream props;
	if (f.getProps(node, props)) {
		//4 byte flags
		//attributes
		//0x01 = version data
		uint32_t flags;
		if (!props.GET_ULONG(flags)) {
			return ERROR_INVALID_FORMAT;
		}

		uint8_t attr;
		if (!props.GET_VALUE(attr)) {
			return ERROR_INVALID_FORMAT;
		}

		if (attr == ROOT_ATTR_VERSION) {
			uint16_t datalen;
			if (!props.GET_VALUE(datalen)) {
				return ERROR_INVALID_FORMAT;
			}

			if (datalen != sizeof(VERSIONINFO)) {
				return ERROR_INVALID_FORMAT;
			}

			VERSIONINFO* vi;
			if (!props.GET_STRUCT(vi)) {
				return ERROR_INVALID_FORMAT;
			}

			Items::dwMajorVersion = vi->dwMajorVersion; //items otb format file version
			Items::dwMinorVersion = vi->dwMinorVersion; //client version
			Items::dwBuildNumber = vi->dwBuildNumber; //revision
		}
	}

	if (Items::dwMajorVersion == 0xFFFFFFFF) {
		std::cout << "[Warning - Items::loadFromOtb] items.otb using generic client version." << std::endl;
	} else if (Items::dwMajorVersion != 3) {
		std::cout << "Old version detected, a newer version of items.otb is required." << std::endl;
		return ERROR_INVALID_FORMAT;
	} else if (Items::dwMinorVersion < CLIENT_VERSION_1035) {
		std::cout << "A newer version of items.otb is required." << std::endl;
		return ERROR_INVALID_FORMAT;
	}

	node = f.getChildNode(node, type);
	while (node != NO_NODE) {
		PropStream stream;
		if (!f.getProps(node, stream)) {
			return f.getError();
		}

		uint32_t flags;
		if (!stream.GET_VALUE(flags)) {
			return ERROR_INVALID_FORMAT;
		}

		uint16_t serverId = 0;
		uint16_t clientId = 0;
		uint16_t speed = 0;
		uint16_t lightLevel = 0;
		uint16_t lightColor = 0;
		uint16_t wareId = 0;
		uint8_t alwaysOnTopOrder = 0;

		uint8_t attrib;
		while (stream.GET_VALUE(attrib)) {
			uint16_t datalen;
			if (!stream.GET_VALUE(datalen)) {
				return ERROR_INVALID_FORMAT;
			}

			switch (attrib) {
				case ITEM_ATTR_SERVERID: {
					if (datalen != sizeof(uint16_t)) {
						return ERROR_INVALID_FORMAT;
					}

					if (!stream.GET_USHORT(serverId)) {
						return ERROR_INVALID_FORMAT;
					}

					if (serverId > 30000 && serverId < 30100) {
						serverId -= 30000;
					}
					break;
				}

				case ITEM_ATTR_CLIENTID: {
					if (datalen != sizeof(uint16_t)) {
						return ERROR_INVALID_FORMAT;
					}

					if (!stream.GET_USHORT(clientId)) {
						return ERROR_INVALID_FORMAT;
					}
					break;
				}

				case ITEM_ATTR_SPEED: {
					if (datalen != sizeof(uint16_t)) {
						return ERROR_INVALID_FORMAT;
					}

					if (!stream.GET_USHORT(speed)) {
						return ERROR_INVALID_FORMAT;
					}
					break;
				}

				case ITEM_ATTR_LIGHT2: {
					if (datalen != sizeof(lightBlock2)) {
						return ERROR_INVALID_FORMAT;
					}

					lightBlock2* lb2;
					if (!stream.GET_STRUCT(lb2)) {
						return ERROR_INVALID_FORMAT;
					}

					lightLevel = lb2->lightLevel;
					lightColor = lb2->lightColor;
					break;
				}

				case ITEM_ATTR_TOPORDER: {
					if (datalen != sizeof(uint8_t)) {
						return ERROR_INVALID_FORMAT;
					}

					if (!stream.GET_UCHAR(alwaysOnTopOrder)) {
						return ERROR_INVALID_FORMAT;
					}
					break;
				}

				case ITEM_ATTR_WAREID: {
					if (datalen != sizeof(uint16_t)) {
						return ERROR_INVALID_FORMAT;
					}

					if (!stream.GET_USHORT(wareId)) {
						return ERROR_INVALID_FORMAT;
					}
					break;
				}

				default: {
					//skip unknown attributes
					if (!stream.SKIP_N(datalen)) {
						return ERROR_INVALID_FORMAT;
					}
					break;
				}
			}
		}

		if (reverseItemMap.find(clientId) == reverseItemMap.end()) {
			reverseItemMap[clientId] = serverId;
		}

		// store the found item
		if (serverId >= items.size()) {
			items.resize(serverId + 1);
		}
		ItemType& iType = items[serverId];

		iType.group = (itemgroup_t)type;
		switch (type) {
			case ITEM_GROUP_CONTAINER:
				iType.type = ITEM_TYPE_CONTAINER;
				break;
			case ITEM_GROUP_DOOR:
				//not used
				iType.type = ITEM_TYPE_DOOR;
				break;
			case ITEM_GROUP_MAGICFIELD:
				//not used
				iType.type = ITEM_TYPE_MAGICFIELD;
				break;
			case ITEM_GROUP_TELEPORT:
				//not used
				iType.type = ITEM_TYPE_TELEPORT;
				break;
			case ITEM_GROUP_NONE:
			case ITEM_GROUP_GROUND:
			case ITEM_GROUP_SPLASH:
			case ITEM_GROUP_FLUID:
			case ITEM_GROUP_CHARGES:
			case ITEM_GROUP_DEPRECATED:
				break;
			default:
				return ERROR_INVALID_FORMAT;
		}

		iType.blockSolid = hasBitSet(FLAG_BLOCK_SOLID, flags);
		iType.blockProjectile = hasBitSet(FLAG_BLOCK_PROJECTILE, flags);
		iType.blockPathFind = hasBitSet(FLAG_BLOCK_PATHFIND, flags);
		iType.hasHeight = hasBitSet(FLAG_HAS_HEIGHT, flags);
		iType.useable = hasBitSet(FLAG_USEABLE, flags);
		iType.pickupable = hasBitSet(FLAG_PICKUPABLE, flags);
		iType.moveable = hasBitSet(FLAG_MOVEABLE, flags);
		iType.stackable = hasBitSet(FLAG_STACKABLE, flags);

		iType.alwaysOnTop = hasBitSet(FLAG_ALWAYSONTOP, flags);
		iType.isVertical = hasBitSet(FLAG_VERTICAL, flags);
		iType.isHorizontal = hasBitSet(FLAG_HORIZONTAL, flags);
		iType.isHangable = hasBitSet(FLAG_HANGABLE, flags);
		iType.allowDistRead = hasBitSet(FLAG_ALLOWDISTREAD, flags);
		iType.rotable = hasBitSet(FLAG_ROTABLE, flags);
		iType.canReadText = hasBitSet(FLAG_READABLE, flags);
		iType.lookThrough = hasBitSet(FLAG_LOOKTHROUGH, flags);
		iType.isAnimation = hasBitSet(FLAG_ANIMATION, flags);
		// iType.walkStack = !hasBitSet(FLAG_FULLTILE, flags);

		iType.id = serverId;
		iType.clientId = clientId;
		iType.speed = speed;
		iType.lightLevel = lightLevel;
		iType.lightColor = lightColor;
		iType.wareId = wareId;
		iType.alwaysOnTopOrder = alwaysOnTopOrder;

		node = f.getNextNode(node, type);
	}

	items.shrink_to_fit();
	return ERROR_NONE;
}
Пример #20
0
bool IOMapSerialize::loadMapBinary(Map* map)
{
	Database* db = Database::getInstance();
	DBResult* result;

	DBQuery query;
	query << "SELECT `house_id`, `data` FROM `house_data` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID);
	if(!(result = db->storeQuery(query.str())))
		return false;

	House* house = NULL;
	do
	{
		int32_t houseId = result->getDataInt("house_id");
		house = Houses::getInstance()->getHouse(houseId);

		uint64_t attrSize = 0;
		const char* attr = result->getDataStream("data", attrSize);

		PropStream propStream;
		propStream.init(attr, attrSize);
		while(propStream.size())
		{
			uint16_t x = 0, y = 0;
			uint8_t z = 0;

			propStream.GET_USHORT(x);
			propStream.GET_USHORT(y);
			propStream.GET_UCHAR(z);

			uint32_t itemCount = 0;
			propStream.GET_ULONG(itemCount);

			Position pos(x, y, (int16_t)z);
			if(house && house->hasPendingTransfer())
			{
				if(Player* player = g_game.getPlayerByGuidEx(house->getOwner()))
				{
					Depot* depot = player->getDepot(player->getTown(), true);
					while(itemCount--)
						loadItem(propStream, depot, true);

					if(player->isVirtual())
					{
						IOLoginData::getInstance()->savePlayer(player);
						delete player;
					}
				}
			}
			else if(Tile* tile = map->getTile(pos))
			{
				while(itemCount--)
					loadItem(propStream, tile, false);
			}
			else
			{
				std::cout << "[Error - IOMapSerialize::loadMapBinary] Unserialization of invalid tile"
					<< " at position " << pos << std::endl;
				break;
			}
 		}
	}
	while(result->next());
	result->free();
 	return true;
}
Пример #21
0
int Items::loadFromOtb(std::string file)
{
	ItemLoader f;
	if(!f.openFile(file.c_str(), false, true)){
		return f.getError();
	}
	
	unsigned long type;
	NODE node = f.getChildNode(NO_NODE, type);
	
	PropStream props;
	if(f.getProps(node,props)){
		//4 byte flags
		//attributes
		//0x01 = version data
		unsigned long flags;
		if(!props.GET_ULONG(flags)){
			return ERROR_INVALID_FORMAT;
		}
		attribute_t attr;
		if(!props.GET_VALUE(attr)){
			return ERROR_INVALID_FORMAT;
		}
		if(attr == ROOT_ATTR_VERSION){
			datasize_t datalen = 0;
			if(!props.GET_VALUE(datalen)){
				return ERROR_INVALID_FORMAT;
			}
			if(datalen != sizeof(VERSIONINFO)){
				return ERROR_INVALID_FORMAT;
			}
			VERSIONINFO *vi;
			if(!props.GET_STRUCT(vi)){
				return ERROR_INVALID_FORMAT;
			}
			Items::dwMajorVersion = vi->dwMajorVersion;	//items otb format file version
			Items::dwMinorVersion = vi->dwMinorVersion; //client version
			Items::dwBuildNumber = vi->dwBuildNumber;	//revision
		}
	}
	
	if(Items::dwMajorVersion != 1){
		std::cout << "Not supported items.otb version." << std::endl;
		return ERROR_INVALID_FORMAT;
	}
	
	if(Items::dwMinorVersion != CLIENT_VERSION_760){
		std::cout << "Not supported items.otb client version." << std::endl;
		return ERROR_INVALID_FORMAT;
	}
	
	node = f.getChildNode(node, type);

	while(node != NO_NODE){
		PropStream props;	
		if(!f.getProps(node,props)){
			return f.getError();	
		}
			
		flags_t flags;
		ItemType* iType = new ItemType();
		iType->group = (itemgroup_t)type;

		switch(type){
		case ITEM_GROUP_NONE:
		case ITEM_GROUP_GROUND:
		case ITEM_GROUP_CONTAINER:
		case ITEM_GROUP_WEAPON:
		case ITEM_GROUP_AMMUNITION:
		case ITEM_GROUP_ARMOR:
		case ITEM_GROUP_RUNE:
		case ITEM_GROUP_TELEPORT:
		case ITEM_GROUP_MAGICFIELD:
		case ITEM_GROUP_WRITEABLE:
		case ITEM_GROUP_KEY:
		case ITEM_GROUP_SPLASH:
		case ITEM_GROUP_FLUID:
		case ITEM_GROUP_DOOR:
			break;
		default:
			return ERROR_INVALID_FORMAT;
			break;
		}

		//read 4 byte flags
		if(!props.GET_VALUE(flags)){
			return ERROR_INVALID_FORMAT;
		}

		iType->blockSolid = ((flags & FLAG_BLOCK_SOLID) == FLAG_BLOCK_SOLID);
		iType->blockProjectile = ((flags & FLAG_BLOCK_PROJECTILE) == FLAG_BLOCK_PROJECTILE);
		iType->blockPathFind = ((flags & FLAG_BLOCK_PATHFIND) == FLAG_BLOCK_PATHFIND);
		iType->hasHeight = ((flags & FLAG_HAS_HEIGHT) == FLAG_HAS_HEIGHT);
		iType->useable = ((flags & FLAG_USEABLE) == FLAG_USEABLE);
		iType->pickupable = ((flags & FLAG_PICKUPABLE) == FLAG_PICKUPABLE);
		iType->moveable = ((flags & FLAG_MOVEABLE) == FLAG_MOVEABLE);
		iType->stackable = ((flags & FLAG_STACKABLE) == FLAG_STACKABLE);
		iType->floorChangeDown = ((flags & FLAG_FLOORCHANGEDOWN) == FLAG_FLOORCHANGEDOWN);
		iType->floorChangeNorth = ((flags & FLAG_FLOORCHANGENORTH) == FLAG_FLOORCHANGENORTH);
		iType->floorChangeEast = ((flags & FLAG_FLOORCHANGEEAST) == FLAG_FLOORCHANGEEAST);
		iType->floorChangeSouth = ((flags & FLAG_FLOORCHANGESOUTH) == FLAG_FLOORCHANGESOUTH);
		iType->floorChangeWest = ((flags & FLAG_FLOORCHANGEWEST) == FLAG_FLOORCHANGEWEST);
		iType->alwaysOnTop = ((flags & FLAG_ALWAYSONTOP) == FLAG_ALWAYSONTOP);
		iType->canDecay = !((flags & FLAG_CANNOTDECAY) == FLAG_CANNOTDECAY);
		iType->isVertical = ((flags & FLAG_VERTICAL) == FLAG_VERTICAL);
		iType->isHorizontal = ((flags & FLAG_HORIZONTAL) == FLAG_HORIZONTAL);
		iType->isHangable = ((flags & FLAG_HANGABLE) == FLAG_HANGABLE);
		iType->allowDistRead = ((flags & FLAG_ALLOWDISTREAD) == FLAG_ALLOWDISTREAD);
							
							
		if(type == ITEM_GROUP_WRITEABLE) {
			iType->RWInfo |= CAN_BE_WRITTEN;
		}

		if((flags & FLAG_READABLE) == FLAG_READABLE)
			iType->RWInfo |= CAN_BE_READ;

		iType->rotable = ((flags & FLAG_ROTABLE) == FLAG_ROTABLE);
		
		attribute_t attrib;
		datasize_t datalen = 0;
		while(props.GET_VALUE(attrib)){
			//size of data
			if(!props.GET_VALUE(datalen)){
				delete iType;
				return ERROR_INVALID_FORMAT;
			}
	
			switch(attrib){
			case ITEM_ATTR_SERVERID:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;
				
				unsigned short serverid;				
				if(!props.GET_USHORT(serverid))
					return ERROR_INVALID_FORMAT;
				
				if(serverid > 20000 && serverid < 20100)
					serverid = serverid - 20000;
						
				iType->id = serverid;
				break;
			}
			case ITEM_ATTR_CLIENTID:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;

				if(!props.GET_USHORT(iType->clientId))
					return ERROR_INVALID_FORMAT;
				
				break;
			}		
			case ITEM_ATTR_NAME:
			{
				char name[128];
				if(datalen >= sizeof(name))
					return ERROR_INVALID_FORMAT;

				if(!props.GET_NSTRING(datalen, iType->name))
					return ERROR_INVALID_FORMAT;
				
				break;
			}	
			case ITEM_ATTR_DESCR:
			{
				char descr[128];
				if(datalen >= sizeof(descr))
					return ERROR_INVALID_FORMAT;
	
				if(!props.GET_NSTRING(datalen, iType->description))
					return ERROR_INVALID_FORMAT;

				break;
			}	
			case ITEM_ATTR_SPEED:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;

				if(!props.GET_USHORT(iType->speed))
					return ERROR_INVALID_FORMAT;

				break;
			}					
			case ITEM_ATTR_SLOT:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;
				
				unsigned short otb_slot;
				
				if(!props.GET_USHORT(otb_slot))
					return ERROR_INVALID_FORMAT;
				
				switch(otb_slot){
				case OTB_SLOT_DEFAULT:
				case OTB_SLOT_WEAPON:
				case OTB_SLOT_HAND:
					//default	
					break;
				case OTB_SLOT_HEAD:
					iType->slot_position = SLOTP_HEAD;
					break;
				case OTB_SLOT_BODY:
					iType->slot_position = SLOTP_ARMOR;
					break;
				case OTB_SLOT_LEGS:
					iType->slot_position = SLOTP_LEGS;
					break;
				case OTB_SLOT_BACKPACK:
					iType->slot_position = SLOTP_BACKPACK;
					break;
				case OTB_SLOT_2HAND:
					iType->slot_position  = SLOTP_TWO_HAND;
					break;
				case OTB_SLOT_FEET:
					iType->slot_position = SLOTP_FEET;
					break;
				case OTB_SLOT_AMULET:
					iType->slot_position = SLOTP_NECKLACE;
					break;
				case OTB_SLOT_RING:
					iType->slot_position = SLOTP_RING;
					break;
					}
				iType->slot_position = iType->slot_position | SLOTP_LEFT | SLOTP_RIGHT | SLOTP_AMMO;
				break;
			}	
			case ITEM_ATTR_MAXITEMS:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;
				
				if(!props.GET_USHORT(iType->maxItems))
					return ERROR_INVALID_FORMAT;

				break;
			}		
			case ITEM_ATTR_WEIGHT:
			{
				if(datalen != sizeof(double))
					return ERROR_INVALID_FORMAT;

				if(!props.GET_VALUE(iType->weight))
					return ERROR_INVALID_FORMAT;

				break;
			}
			case ITEM_ATTR_MAGLEVEL:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;
					
				unsigned short maglev;
				if(!props.GET_USHORT(maglev))
					return ERROR_INVALID_FORMAT;
				
				iType->runeMagLevel = maglev;
				break;
			}
			case ITEM_ATTR_MAGFIELDTYPE:
			{
				if(datalen != sizeof(unsigned char))
					return ERROR_INVALID_FORMAT;
				
				unsigned char fieldtype;
				if(!props.GET_UCHAR(fieldtype))
					return ERROR_INVALID_FORMAT;

				iType->magicfieldtype = fieldtype;
				break;
			}	
			case ITEM_ATTR_ROTATETO:
			{
				if(datalen != sizeof(unsigned short))
					return ERROR_INVALID_FORMAT;
				
				unsigned short rotate;
				if(!props.GET_USHORT(rotate))
					return ERROR_INVALID_FORMAT;
				
				iType->rotateTo = rotate;
				break;
			}	
			case ITEM_ATTR_DECAY2:
			{
				if(datalen != sizeof(decayBlock2))
					return ERROR_INVALID_FORMAT;

				decayBlock2* db2;
				if(!props.GET_STRUCT(db2))
					return ERROR_INVALID_FORMAT;
				
				iType->decayTime = db2->decayTime;
				iType->decayTo = db2->decayTo;
				break;
			}	
			case ITEM_ATTR_WEAPON2:
			{
				if(datalen != sizeof(weaponBlock2))
					return ERROR_INVALID_FORMAT;

				weaponBlock2* wb2;
				if(!props.GET_STRUCT(wb2))
					return ERROR_INVALID_FORMAT;
				
				iType->weaponType = (WeaponType_t)wb2->weaponType;
				iType->shootType = translateOTBShootType((ShootTypeOtb_t)wb2->shootType);
				iType->amuType = (Ammo_t)wb2->amuType;
				iType->attack = wb2->attack;
				iType->defence = wb2->defence;
				break;
			}
			case ITEM_ATTR_AMU2:
			{
				if(datalen != sizeof(amuBlock2))
					return ERROR_INVALID_FORMAT;

				amuBlock2* ab2;
				if(!props.GET_STRUCT(ab2))
					return ERROR_INVALID_FORMAT;
					
				iType->weaponType = WEAPON_AMMO;
				iType->shootType = translateOTBShootType((ShootTypeOtb_t)ab2->shootType);
				iType->amuType = (Ammo_t)ab2->amuType;
				iType->attack = ab2->attack;
				break;
			}
			case ITEM_ATTR_ARMOR2:
			{
				if(datalen != sizeof(armorBlock2))
					return ERROR_INVALID_FORMAT;

				armorBlock2* ab2;
				if(!props.GET_STRUCT(ab2))
					return ERROR_INVALID_FORMAT;
				
				iType->armor = ab2->armor;
				iType->weight = ab2->weight;
				//ignore this value
				//iType->slot_position = (slots_t)ab2.slot_position;

				break;
			}
			case ITEM_ATTR_WRITEABLE3:
			{
				if(datalen != sizeof(writeableBlock3))
					return ERROR_INVALID_FORMAT;

				writeableBlock3* wb3;
				if(!props.GET_STRUCT(wb3))
					return ERROR_INVALID_FORMAT;
					
				iType->readOnlyId = wb3->readOnlyId;
				iType->maxTextLen = wb3->maxTextLen;

				break;
			}	
			case ITEM_ATTR_LIGHT2:
			{
				if(datalen != sizeof(lightBlock2))
					return ERROR_INVALID_FORMAT;

				lightBlock2* lb2;
				if(!props.GET_STRUCT(lb2))
					return ERROR_INVALID_FORMAT;
			
				iType->lightLevel = lb2->lightLevel;
				iType->lightColor = lb2->lightColor;
				break;
			}
			case ITEM_ATTR_TOPORDER:
			{
				if(datalen != sizeof(unsigned char))
					return ERROR_INVALID_FORMAT;
				
				if(!props.GET_UCHAR(iType->alwaysOnTopOrder))
					return ERROR_INVALID_FORMAT;
				break;
			}
			default:
				//skip unknown attributes
				if(!props.SKIP_N(datalen))
					return ERROR_INVALID_FORMAT;
				break;
			}
		}
		
		//get rune mag level from spells.xml
		if(iType->group == ITEM_GROUP_RUNE){
			/*
			std::map<unsigned short, Spell*>::iterator it = spells.getAllRuneSpells()->find(iType->id);
			if(it != spells.getAllRuneSpells()->end()){
				iType->runeMagLevel = it->second->getMagLv();
			}
			else{
				iType->runeMagLevel = 0;
			}
			*/
		}

		// store the found item	 
		items[iType->id] = iType;
		//revItems[iType->clientId] = iType->id;
		
		node = f.getNextNode(node, type);
	}
	
	return ERROR_NONE;
}
Пример #22
0
Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream& propStream)
{
	switch (attr) {
		case ATTR_COUNT: {
			uint8_t _count = 0;

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

			setSubType(_count);
			break;
		}

		case ATTR_ACTION_ID: {
			uint16_t _actionid = 0;

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

			setActionId(_actionid);
			break;
		}

		case ATTR_UNIQUE_ID: {
			uint16_t _uniqueid;

			if (!propStream.GET_USHORT(_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_ULONG(_writtenDate)) {
				return ATTR_READ_ERROR;
			}

			setDate(_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_UCHAR(_charges)) {
				return ATTR_READ_ERROR;
			}

			setSubType(_charges);
			break;
		}

		case ATTR_CHARGES: {
			uint16_t _charges = 1;

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

			setSubType(_charges);
			break;
		}

		case ATTR_DURATION: {
			uint32_t duration = 0;

			if (!propStream.GET_ULONG(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_UCHAR(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_USHORT(_depotId)) {
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}

		//Door class
		case ATTR_HOUSEDOORID: {
			uint8_t _doorId;

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

			return ATTR_READ_CONTINUE;
		}

		//Bed class
		case ATTR_SLEEPERGUID: {
			uint32_t _guid;

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

			return ATTR_READ_CONTINUE;
		}

		case ATTR_SLEEPSTART: {
			uint32_t sleep_start;

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

			return ATTR_READ_CONTINUE;
		}

		//Teleport class
		case ATTR_TELE_DEST: {
			TeleportDest* tele_dest;

			if (!propStream.GET_STRUCT(tele_dest)) {
				return ATTR_READ_ERROR;
			}

			return ATTR_READ_CONTINUE;
		}

		//Container class
		case ATTR_CONTAINER_ITEMS: {
			uint32_t count;

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

			return ATTR_READ_ERROR;
		}

		default:
			return ATTR_READ_ERROR;
	}

	return ATTR_READ_CONTINUE;
}