bool Container::unserializeItemNode_OTMM(const IOMap& maphandle, BinaryNode* node) { bool ret = Item::unserializeAttributes_OTMM(maphandle, node); if(ret) { BinaryNode* child = node->getChild(); if(child) do { uint8_t type; if(!child->getByte(type)) { return false; } //load container items if(type == OTMM_ITEM) { Item* item = Item::Create_OTMM(maphandle, child); if(!item) { return false; } if(!item->unserializeItemNode_OTMM(maphandle, child)) { delete item; return false; } contents.push_back(item); } else { // corrupted file data! return false; } } while(child->advance()); return true; } return false; }
void LiveSocket::receiveFloor(NetworkMessage& message, Editor& editor, Action* action, int32_t ndx, int32_t ndy, int32_t z, QTreeNode* node, Floor* floor) { Map& map = editor.map; uint16_t tileBits = message.read<uint16_t>(); if(tileBits == 0) { for(uint_fast8_t x = 0; x < 4; ++x) { for(uint_fast8_t y = 0; y < 4; ++y) { action->addChange(new Change(map.allocator(node->createTile(ndx * 4 + x, ndy * 4 + y, z)))); } } return; } // -1 on address since we skip the first START_NODE when sending const std::string& data = message.read<std::string>(); mapReader.assign(reinterpret_cast<const uint8_t*>(data.c_str() - 1), data.size()); BinaryNode* rootNode = mapReader.getRootNode(); BinaryNode* tileNode = rootNode->getChild(); Position position(0, 0, z); for(uint_fast8_t x = 0; x < 4; ++x) { for(uint_fast8_t y = 0; y < 4; ++y) { position.x = (ndx * 4) + x; position.y = (ndy * 4) + y; if(testFlags(tileBits, 1 << ((x * 4) + y))) { receiveTile(tileNode, editor, action, &position); tileNode->advance(); } else { action->addChange(new Change(map.allocator(node->createTile(position.x, position.y, z)))); } } } mapReader.close(); }
void LiveServer::OnReceiveChanges(LivePeer* connection, NetworkMessage* nmsg) { std::string data = nmsg->ReadString(); // -1 on address since we skip the first START_NODE when sending bn_reader.assign((uint8_t*)data.c_str() - 1, data.size()); BinaryNode* rootNode = bn_reader.getRootNode(); BinaryNode* tileNode = rootNode->getChild(); NetworkedAction* action = dynamic_cast<NetworkedAction*>(editor->actionQueue->createAction(ACTION_REMOTE)); action->owner = connection->GetClientID(); if (tileNode) do { Tile* t = ReadTile(tileNode, editor->map); if(!t) continue; action->addChange(newd Change(t)); } while (tileNode->advance()); bn_reader.close(); editor->actionQueue->addAction(action); gui.RefreshView(); }
Tile* LiveSocket::readTile(BinaryNode* node, Editor& editor, const Position* position) { ASSERT(node != nullptr); Map& map = editor.map; uint8_t tileType; node->getByte(tileType); if(tileType != OTBM_TILE && tileType != OTBM_HOUSETILE) { return nullptr; } Position pos; if(position) { pos = *position; } else { uint16_t x; node->getU16(x); pos.x = x; uint16_t y; node->getU16(y); pos.y = y; uint8_t z; node->getU8(z); pos.z = z; } Tile* tile = map.allocator( map.createTileL(pos) ); if(tileType == OTBM_HOUSETILE) { uint32_t houseId; if(!node->getU32(houseId)) { //warning(wxT("House tile without house data, discarding tile")); delete tile; return nullptr; } if(houseId) { House* house = map.houses.getHouse(houseId); if(house) { tile->setHouse(house); } } else { //warning(wxT("Invalid house id from tile %d:%d:%d"), pos.x, pos.y, pos.z); } } uint8_t attribute; while(node->getU8(attribute)) { switch (attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags = 0; if(!node->getU32(flags)) { //warning(wxT("Invalid tile flags of tile on %d:%d:%d"), pos.x, pos.y, pos.z); } tile->setMapFlags(flags); break; } case OTBM_ATTR_ITEM: { Item* item = Item::Create_OTBM(mapVersion, node); if(!item) { //warning(wxT("Invalid item at tile %d:%d:%d"), pos.x, pos.y, pos.z); } tile->addItem(item); break; } default: //warning(wxT("Unknown tile attribute at %d:%d:%d"), pos.x, pos.y, pos.z); break; } } //for(BinaryNode* itemNode = node->getChild(); itemNode; itemNode->advance()) { BinaryNode* itemNode = node->getChild(); if(itemNode) do { uint8_t itemType; if(!itemNode->getByte(itemType)) { //warning(wxT("Unknown item type %d:%d:%d"), pos.x, pos.y, pos.z); delete tile; return nullptr; } if(itemType == OTBM_ITEM) { Item* item = Item::Create_OTBM(mapVersion, itemNode); if(item) { if(!item->unserializeItemNode_OTBM(mapVersion, itemNode)) { //warning(wxT("Couldn't unserialize item attributes at %d:%d:%d"), pos.x, pos.y, pos.z); } tile->addItem(item); } } else { //warning(wxT("Unknown type of tile child node")); } //} } while(itemNode->advance()); return tile; }
bool IOMapOTMM::loadMap(Map& map, NodeFileReadHandle& f, const FileName& identifier, bool showdialog) { BinaryNode* root = f.getRootNode(); if(!root) { error(wxT("Could not read root node.")); return false; } root->skip(1); // Skip the type byte uint8_t u8; uint16_t u16; uint32_t u32; if(!root->getU32(u32) || u32 != 1) { // Version error(wxT("Unsupported or damaged map version.")); return false; } if(!root->getU16(u16)) { error(wxT("Could not read root header.")); return false; } map.width = u16; if(!root->getU16(u16)) { error(wxT("Could not read root header.")); return false; } map.height = u16; if(!root->getU32(u32) || u32 > (unsigned long)item_db.MajorVersion) { // OTB major version if(queryUser(wxT("Map error"), wxT("The loaded map appears to be a items.otb format that deviates from the items.otb loaded by the editor. Do you still want to attempt to load the map?"))) { warning(wxT("Unsupported or damaged map version")); } else { error(wxT("Outdated items.otb, could not load map.")); return false; } } if(!root->getU32(u32) || u32 > (unsigned long)item_db.MinorVersion) { // OTB minor version warning(wxT("The editor needs an updated items.otb version.")); } BinaryNode* mapHeaderNode = root->getChild(); if(mapHeaderNode == NULL || !mapHeaderNode->getByte(u8) || u8 != OTMM_MAP_DATA) { error(wxT("Could not get root child node. Cannot recover from fatal error!")); return false; } int nodes_loaded = 0; BinaryNode* mapNode = mapHeaderNode->getChild(); if(mapNode) do { ++nodes_loaded; if(showdialog && nodes_loaded % 15 == 0) { gui.SetLoadDone(int(100.0 * f.tell() / f.size())); } uint8_t node_type; if(!mapNode->getByte(node_type)) { warning(wxT("Invalid map node")); continue; } switch(node_type) { case OTMM_EDITOR: { } break; case OTMM_DESCRIPTION: { std::string desc; mapNode->getString(desc); map.setMapDescription(desc); } break; case OTMM_TILE_DATA: { BinaryNode* tileNode = mapNode->getChild(); if(tileNode) do { Tile* tile = NULL; uint8_t tile_type; if(!tileNode->getByte(tile_type)) { warning(wxT("Invalid tile type")); continue; } if(tile_type != OTMM_TILE && tile_type != OTMM_HOUSETILE) { warning(wxT("Unknown type of tile node")); continue; } uint16_t x_offset, y_offset; uint8_t z_offset; if(!tileNode->getU16(x_offset) || !tileNode->getU16(y_offset) || !tileNode->getU8(z_offset) ) { warning(wxT("Could not read position of tile")); continue; } const Position pos(x_offset, y_offset, z_offset); if(map.getTile(pos)) { warning(wxT("Duplicate tile at %d:%d:%d, discarding duplicate"), pos.x, pos.y, pos.z); continue; } tile = map.allocator(pos); House* house = NULL; if(tile_type == OTMM_HOUSETILE) { uint32_t house_id; if(!tileNode->getU32(house_id)) { warning(wxT("House tile without house data, discarding tile")); continue; } if(house_id) { house = map.houses.getHouse(house_id); if(!house) { house = newd House(map); house->id = house_id; map.houses.addHouse(house); } } else { warning(wxT("Invalid house id from tile %d:%d:%d"), pos.x, pos.y, pos.z); } } uint16_t ground_id; tileNode->getU16(ground_id); if(ground_id != 0) { tile->addItem(Item::Create(ground_id)); } uint8_t attribute; while(tileNode->getU8(attribute)) { switch(attribute) { case OTMM_ATTR_TILE_FLAGS: { uint32_t flags = 0; if(!tileNode->getU32(flags)) { warning(wxT("Invalid tile flags of tile on %d:%d:%d"), pos.x, pos.y, pos.z); } tile->setMapFlags(flags); } break; default: { warning(wxT("Unknown tile attribute at %d:%d:%d"), pos.x, pos.y, pos.z); } break; } } BinaryNode* itemNode = tileNode->getChild(); if(itemNode) do { Item* item = NULL; uint8_t item_type; if(!itemNode->getByte(item_type)) { warning(wxT("Unknown item type %d:%d:%d"), pos.x, pos.y, pos.z); continue; } if(item_type == OTMM_ITEM) { item = Item::Create_OTMM(*this, itemNode); if(item) { if(item->unserializeItemNode_OTMM(*this, itemNode) == false) { warning(wxT("Couldn't unserialize item attributes at %d:%d:%d"), pos.x, pos.y, pos.z); } tile->addItem(item); } } else { warning(wxT("Unknown type of tile child node")); } } while(itemNode->advance()); tile->update(); if(house) { house->addTile(tile); } map.setTile(pos, tile); } while(tileNode->advance()); } break; case OTMM_SPAWN_DATA: { BinaryNode* spawnNode = mapNode->getChild(); if(spawnNode) do { uint8_t spawn_type; if(!spawnNode->getByte(spawn_type)) { warning(wxT("Could not read spawn type.")); continue; } if(spawn_type != OTMM_SPAWN_AREA) { warning(wxT("Invalid spawn type.")); continue; } // Read position uint16_t spawn_x, spawn_y; uint8_t spawn_z; uint32_t radius; if(!spawnNode->getU16(spawn_x) || !spawnNode->getU16(spawn_y) || !spawnNode->getU8(spawn_z) ) { warning(wxT("Could not read spawn position.")); continue; } const Position spawnpos(spawn_x, spawn_y, spawn_z); // Read radius if(!spawnNode->getU32(radius)) { warning(wxT("Could not read spawn radius.")); continue; } // Adjust radius radius = min(radius, uint32_t(settings.getInteger(Config::MAX_SPAWN_RADIUS))); // Create and assign spawn Tile* spawn_tile = map.getTile(spawnpos); if(spawn_tile && spawn_tile->spawn) { warning(wxT("Duplicate spawn on position %d:%d:%d\n"), spawn_tile->getX(), spawn_tile->getY(), spawn_tile->getZ()); continue; } Spawn* spawn = newd Spawn(radius); if(!spawn_tile) { spawn_tile = map.allocator(spawnpos); map.setTile(spawnpos, spawn_tile); } spawn_tile->spawn = spawn; map.addSpawn(spawn_tile); // Read any creatures associated with the spawn BinaryNode* creatureNode = spawnNode->getChild(); if(creatureNode) do { uint8_t creature_type; if(!creatureNode->getByte(creature_type)) { warning(wxT("Could not read type of creature node.")); continue; } bool isNPC; std::string name; uint32_t spawntime = 0; // Only applicable for monsters if(creature_type == OTMM_NPC) { isNPC = true; if(!creatureNode->getString(name)) { warning(wxT("Could not read name of NPC.")); return false; } } else if(creature_type == OTMM_MONSTER) { isNPC = false; if(!creatureNode->getString(name)) { warning(wxT("Could not read name of monster.")); return false; } if(!creatureNode->getU32(spawntime)) { warning(wxT("Could not read spawn time of monster.")); return false; } } else { warning(wxT("Unknown creature node type (0x%.2x)."), creature_type); return false; } // Read creature position uint16_t creature_x, creature_y; uint8_t creature_z; if(!creatureNode->getU16(creature_x) || !creatureNode->getU16(creature_y) || !creatureNode->getU8(creature_z) ) { warning(wxT("Could not read creature position.")); continue; } const Position creaturepos(creature_x, creature_y, creature_z); // Check radius if(uint32_t(abs(creaturepos.x - spawnpos.x)) > radius || uint32_t(abs(creaturepos.y - spawnpos.y)) > radius) { // Outside of the spawn... } // Create creature and put on map Tile* creature_tile; if(creaturepos == spawnpos) { creature_tile = spawn_tile; } else { creature_tile = map.getTile(creaturepos); } if(!creature_tile) { warning(wxT("Discarding creature \"%s\" at %d:%d:%d due to invalid position"), name.c_str(), creaturepos.x, creaturepos.y, creaturepos.z); break; } if(creature_tile->creature) { warning(wxT("Duplicate creature \"%s\" at %d:%d:%d, discarding"), name.c_str(), creaturepos.x, creaturepos.y, creaturepos.z); break; } CreatureType* type = creature_db[name]; if(!type) { type = creature_db.addMissingCreatureType(name, isNPC); } Creature* creature = newd Creature(type); creature->setSpawnTime(spawntime); creature_tile->creature = creature; if(creature_tile->spawn_count == 0) { // No spawn, create a newd one (this happends if the radius of the spawn has been decreased due to settings) ASSERT(creature_tile->spawn == NULL); Spawn* spawn = newd Spawn(5); creature_tile->spawn = spawn; map.addSpawn(creature_tile); } } while(creatureNode->advance()); } while(spawnNode->advance()); } break; case OTMM_TOWN_DATA: { BinaryNode* townNode = mapNode->getChild(); if(townNode) do { uint8_t town_type; if(!townNode->getByte(town_type)) { warning(wxT("Could not read town type")); continue; } if(town_type != OTMM_TOWN) { warning(wxT("Unknown town type")); continue; } uint32_t town_id; if(!townNode->getU32(town_id)) { warning(wxT("Invalid town id")); continue; } Town* town = map.towns.getTown(town_id); if(town) { warning(wxT("Duplicate town id %d, discarding duplicate"), town_id); continue; } else { town = newd Town(town_id); if(!map.towns.addTown(town)) { delete town; continue; } } std::string town_name; if(!townNode->getString(town_name)) { warning(wxT("Invalid town name")); continue; } town->setName(town_name); Position pos; uint16_t x; uint16_t y; uint8_t z; if(!townNode->getU16(x) || !townNode->getU16(y) || !townNode->getU8(z)) { warning(wxT("Invalid town temple position")); continue; } pos.x = x; pos.y = y; pos.z = z; town->setTemplePosition(pos); } while(townNode->advance()); } break; case OTMM_HOUSE_DATA: { BinaryNode* houseNode = mapNode->getChild(); if(houseNode) do { uint8_t house_type; if(!houseNode->getByte(house_type)) { warning(wxT("Could not read house type")); continue; } if(house_type != OTMM_HOUSE) { warning(wxT("Unknown house type.")); continue; } uint32_t house_id; if(!houseNode->getU32(house_id)) { warning(wxT("Could not read house id.")); continue; } House* house = map.houses.getHouse(house_id); if(!house) { continue; } std::string house_name; if(!houseNode->getString(house_name)) { warning(wxT("Could not read house name.")); continue; } uint32_t town_id; if(!houseNode->getU32(town_id)) { warning(wxT("Could not read house town id.")); continue; } uint32_t rent; if(!houseNode->getU32(rent)) { warning(wxT("Could not read house rent.")); continue; } house->name = house_name; house->townid = town_id; house->rent = rent; uint16_t x; uint16_t y; uint8_t z; if(!houseNode->getU16(x) || !houseNode->getU16(y) || !houseNode->getU8(z)) { warning(wxT("Invalid town temple position")); continue; } house->setExit(Position(x, y, z)); } while(houseNode->advance()); } break; } } while(mapNode->advance()); return true; }