DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, std::string name, uint32 guid) { uint32 charcount = AccountMgr::GetCharactersCount(account); if (charcount >= 10) return DUMP_TOO_MANY_CHARS; FILE *fin = fopen(file.c_str(), "r"); if (!fin) return DUMP_FILE_OPEN_ERROR; QueryResult result = QueryResult(NULL); char newguid[20], chraccount[20], newpetid[20], currpetid[20], lastpetid[20]; // make sure the same guid doesn't already exist and is safe to use bool incHighest = true; if (guid != 0 && guid < sObjectMgr->m_hiCharGuid) { result = CharacterDatabase.PQuery("SELECT 1 FROM characters WHERE guid = '%d'", guid); if (result) guid = sObjectMgr->m_hiCharGuid; // use first free if exists else incHighest = false; } else guid = sObjectMgr->m_hiCharGuid; // normalize the name if specified and check if it exists if (!normalizePlayerName(name)) name = ""; if (ObjectMgr::CheckPlayerName(name, true) == CHAR_NAME_SUCCESS) { CharacterDatabase.EscapeString(name); // for safe, we use name only for sql quearies anyway result = CharacterDatabase.PQuery("SELECT 1 FROM characters WHERE name = '%s'", name.c_str()); if (result) name = ""; // use the one from the dump } else name = ""; // name encoded or empty snprintf(newguid, 20, "%u", guid); snprintf(chraccount, 20, "%u", account); snprintf(newpetid, 20, "%u", sObjectMgr->GeneratePetNumber()); snprintf(lastpetid, 20, "%s", ""); std::map<uint32, uint32> items; std::map<uint32, uint32> mails; char buf[32000] = ""; typedef std::map<uint32, uint32> PetIds; // old->new petid relation typedef PetIds::value_type PetIdsPair; PetIds petids; SQLTransaction trans = CharacterDatabase.BeginTransaction(); while (!feof(fin)) { if (!fgets(buf, 32000, fin)) { if (feof(fin)) break; ROLLBACK(DUMP_FILE_BROKEN); } std::string line; line.assign(buf); // skip empty strings size_t nw_pos = line.find_first_not_of(" \t\n\r\7"); if (nw_pos == std::string::npos) continue; // skip logfile-side dump start notice, the important notes and dump end notices if ((line.substr(nw_pos, 16) == "== START DUMP ==") || (line.substr(nw_pos, 15) == "IMPORTANT NOTE:") || (line.substr(nw_pos, 14) == "== END DUMP ==")) continue; // add required_ check /* if (line.substr(nw_pos, 41) == "UPDATE character_db_version SET required_") { if (!CharacterDatabase.Execute(line.c_str())) ROLLBACK(DUMP_FILE_BROKEN); continue; } */ // determine table name and load type std::string tn = gettablename(line); if (tn.empty()) { sLog->outError("LoadPlayerDump: Can't extract table name from line: '%s'!", line.c_str()); ROLLBACK(DUMP_FILE_BROKEN); } DumpTableType type = DumpTableType(0); uint8 i; for (i = 0; i < DUMP_TABLE_COUNT; ++i) { if (tn == dumpTables[i].name) { type = dumpTables[i].type; break; } } if (i == DUMP_TABLE_COUNT) { sLog->outError("LoadPlayerDump: Unknown table: '%s'!", tn.c_str()); ROLLBACK(DUMP_FILE_BROKEN); } // change the data to server values switch (type) { case DTT_CHARACTER: { if (!changenth(line, 1, newguid)) // characters.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 2, chraccount)) // characters.account update ROLLBACK(DUMP_FILE_BROKEN); if (name == "") { // check if the original name already exists name = getnth(line, 3); CharacterDatabase.EscapeString(name); result = CharacterDatabase.PQuery("SELECT 1 FROM characters WHERE name = '%s'", name.c_str()); if (result) { if (!changenth(line, 37, "1")) // characters.at_login set to "rename on login" ROLLBACK(DUMP_FILE_BROKEN); } } else if (!changenth(line, 3, name.c_str())) // characters.name ROLLBACK(DUMP_FILE_BROKEN); const char null[5] = "NULL"; if (!changenth(line, 69, null)) // characters.deleteInfos_Account ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 70, null)) // characters.deleteInfos_Name ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 71, null)) // characters.deleteDate ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_CHAR_TABLE: { if (!changenth(line, 1, newguid)) // character_*.guid update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_EQSET_TABLE: { if (!changenth(line, 1, newguid)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.guid char newSetGuid[24]; snprintf(newSetGuid, 24, UI64FMTD, sObjectMgr->GenerateEquipmentSetGuid()); if (!changenth(line, 2, newSetGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.setguid break; } case DTT_INVENTORY: { if (!changenth(line, 1, newguid)) // character_inventory.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!changeGuid(line, 2, items, sObjectMgr->m_hiItemGuid, true)) ROLLBACK(DUMP_FILE_BROKEN); // character_inventory.bag update if (!changeGuid(line, 4, items, sObjectMgr->m_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_inventory.item update break; } case DTT_MAIL: // mail { if (!changeGuid(line, 1, mails, sObjectMgr->m_mailid)) ROLLBACK(DUMP_FILE_BROKEN); // mail.id update if (!changenth(line, 6, newguid)) // mail.receiver update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_MAIL_ITEM: // mail_items { if (!changeGuid(line, 1, mails, sObjectMgr->m_mailid)) ROLLBACK(DUMP_FILE_BROKEN); // mail_items.id if (!changeGuid(line, 2, items, sObjectMgr->m_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // mail_items.item_guid if (!changenth(line, 3, newguid)) // mail_items.receiver ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_ITEM: { // item, owner, data field:item, owner guid if (!changeGuid(line, 1, items, sObjectMgr->m_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // item_instance.guid update if (!changenth(line, 3, newguid)) // item_instance.owner_guid update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_ITEM_GIFT: { if (!changenth(line, 1, newguid)) // character_gifts.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!changeGuid(line, 2, items, sObjectMgr->m_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_gifts.item_guid update break; } case DTT_PET: { //store a map of old pet id to new inserted pet id for use by type 5 tables snprintf(currpetid, 20, "%s", getnth(line, 1).c_str()); if (*lastpetid == '\0') snprintf(lastpetid, 20, "%s", currpetid); if (strcmp(lastpetid, currpetid) != 0) { snprintf(newpetid, 20, "%d", sObjectMgr->GeneratePetNumber()); snprintf(lastpetid, 20, "%s", currpetid); } std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid)); if (petids_iter == petids.end()) { petids.insert(PetIdsPair(atoi(currpetid), atoi(newpetid))); } if (!changenth(line, 1, newpetid)) // character_pet.id update ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 3, newguid)) // character_pet.owner update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_PET_TABLE: // pet_aura, pet_spell, pet_spell_cooldown { snprintf(currpetid, 20, "%s", getnth(line, 1).c_str()); // lookup currpetid and match to new inserted pet id std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid)); if (petids_iter == petids.end()) // couldn't find new inserted id ROLLBACK(DUMP_FILE_BROKEN); snprintf(newpetid, 20, "%d", petids_iter->second); if (!changenth(line, 1, newpetid)) ROLLBACK(DUMP_FILE_BROKEN); break; } default: sLog->outError("Unknown dump table type: %u", type); break; } fixNULLfields(line); trans->Append(line.c_str()); } CharacterDatabase.CommitTransaction(trans); sObjectMgr->m_hiItemGuid += items.size(); sObjectMgr->m_mailid += mails.size(); if (incHighest) ++sObjectMgr->m_hiCharGuid; fclose(fin); return DUMP_SUCCESS; }
DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, std::string name, ObjectGuid::LowType guid) { uint32 charcount = AccountMgr::GetCharactersCount(account); if (charcount >= 10) return DUMP_TOO_MANY_CHARS; FILE* fin = fopen(file.c_str(), "r"); if (!fin) return DUMP_FILE_OPEN_ERROR; char newguid[20], chraccount[20]; // make sure the same guid doesn't already exist and is safe to use bool incHighest = true; if (guid && guid < sObjectMgr->GetGenerator<HighGuid::Player>().GetNextAfterMaxUsed()) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_GUID); stmt->setUInt32(0, guid); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) guid = sObjectMgr->GetGenerator<HighGuid::Player>().GetNextAfterMaxUsed(); // use first free if exists else incHighest = false; } else guid = sObjectMgr->GetGenerator<HighGuid::Player>().GetNextAfterMaxUsed(); // normalize the name if specified and check if it exists if (!normalizePlayerName(name)) name.clear(); if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) == CHAR_NAME_SUCCESS) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) name.clear(); // use the one from the dump } else name.clear(); // name encoded or empty snprintf(newguid, 20, "%u", guid); snprintf(chraccount, 20, "%u", account); DumpGuidMap items; DumpGuidMap mails; char buf[32000]; memset(buf, 0, sizeof(buf)); typedef std::map<uint32 /*old*/, uint32 /*new*/> PetIds; PetIds petIds; uint8 gender = GENDER_NONE; uint8 race = RACE_NONE; uint8 playerClass = 0; uint8 level = 1; ObjectGuid::LowType itemLowGuidOffset = sObjectMgr->GetGenerator<HighGuid::Item>().GetNextAfterMaxUsed(); SQLTransaction trans = CharacterDatabase.BeginTransaction(); while (!feof(fin)) { if (!fgets(buf, 32000, fin)) { if (feof(fin)) break; ROLLBACK(DUMP_FILE_BROKEN); } std::string line; line.assign(buf); // skip empty strings size_t nw_pos = line.find_first_not_of(" \t\n\r\7"); if (nw_pos == std::string::npos) continue; // skip logfile-side dump start notice, the important notes and dump end notices if ((line.substr(nw_pos, 16) == "== START DUMP ==") || (line.substr(nw_pos, 15) == "IMPORTANT NOTE:") || (line.substr(nw_pos, 14) == "== END DUMP ==")) continue; // add required_ check /* if (line.substr(nw_pos, 41) == "UPDATE character_db_version SET required_") { if (!CharacterDatabase.Execute(line.c_str())) ROLLBACK(DUMP_FILE_BROKEN); continue; } */ // determine table name and load type std::string tn = GetTableName(line); if (tn.empty()) { TC_LOG_ERROR("misc", "LoadPlayerDump: Can't extract table name from line: '%s'!", line.c_str()); ROLLBACK(DUMP_FILE_BROKEN); } DumpTableType type = DumpTableType(0); uint8 i; for (i = 0; i < DUMP_TABLE_COUNT; ++i) { if (tn == dumpTables[i].name) { type = dumpTables[i].type; break; } } if (i == DUMP_TABLE_COUNT) { TC_LOG_ERROR("misc", "LoadPlayerDump: Unknown table: '%s'!", tn.c_str()); ROLLBACK(DUMP_FILE_BROKEN); } // change the data to server values switch (type) { case DTT_CHARACTER: { if (!ChangeNth(line, 1, newguid)) // characters.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeNth(line, 2, chraccount)) // characters.account update ROLLBACK(DUMP_FILE_BROKEN); race = uint8(atoul(GetNth(line, 4).c_str())); playerClass = uint8(atoul(GetNth(line, 5).c_str())); gender = uint8(atoul(GetNth(line, 6).c_str())); level = uint8(atoul(GetNth(line, 7).c_str())); if (name.empty()) { // check if the original name already exists name = GetNth(line, 3); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) if (!ChangeNth(line, 37, "1")) // characters.at_login set to "rename on login" ROLLBACK(DUMP_FILE_BROKEN); } else if (!ChangeNth(line, 3, name.c_str())) // characters.name ROLLBACK(DUMP_FILE_BROKEN); const char null[5] = "NULL"; if (!ChangeNth(line, 74, null)) // characters.deleteInfos_Account ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeNth(line, 75, null)) // characters.deleteInfos_Name ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeNth(line, 76, null)) // characters.deleteDate ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_CHAR_TABLE: { if (!ChangeNth(line, 1, newguid)) // character_*.guid update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_EQSET_TABLE: { if (!ChangeNth(line, 1, newguid)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.guid char newSetGuid[24]; snprintf(newSetGuid, 24, UI64FMTD, sObjectMgr->GenerateEquipmentSetGuid()); if (!ChangeNth(line, 2, newSetGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.setguid for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot) if (!ChangeGuid(line, 7 + slot, items, itemLowGuidOffset, true)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.item break; } case DTT_INVENTORY: { if (!ChangeNth(line, 1, newguid)) // character_inventory.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeGuid(line, 2, items, itemLowGuidOffset, true)) ROLLBACK(DUMP_FILE_BROKEN); // character_inventory.bag update if (!ChangeGuid(line, 4, items, itemLowGuidOffset)) ROLLBACK(DUMP_FILE_BROKEN); // character_inventory.item update break; } case DTT_MAIL: // mail { if (!ChangeGuid(line, 1, mails, sObjectMgr->_mailId)) ROLLBACK(DUMP_FILE_BROKEN); // mail.id update if (!ChangeNth(line, 6, newguid)) // mail.receiver update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_MAIL_ITEM: // mail_items { if (!ChangeGuid(line, 1, mails, sObjectMgr->_mailId)) ROLLBACK(DUMP_FILE_BROKEN); // mail_items.id if (!ChangeGuid(line, 2, items, itemLowGuidOffset)) ROLLBACK(DUMP_FILE_BROKEN); // mail_items.item_guid if (!ChangeNth(line, 3, newguid)) // mail_items.receiver ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_ITEM: { // item, owner, data field:item, owner guid if (!ChangeGuid(line, 1, items, itemLowGuidOffset)) ROLLBACK(DUMP_FILE_BROKEN); // item_instance.guid update if (!ChangeNth(line, 3, newguid)) // item_instance.owner_guid update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_ITEM_GIFT: { if (!ChangeNth(line, 1, newguid)) // character_gifts.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeGuid(line, 2, items, itemLowGuidOffset)) ROLLBACK(DUMP_FILE_BROKEN); // character_gifts.item_guid update break; } case DTT_PET: { // store a map of old pet id to new inserted pet id for use by DTT_PET_TABLE tables std::string petIdStr = GetNth(line, 1); uint32 currentPetId = atoul(petIdStr.c_str()); PetIds::const_iterator petIdsItr = petIds.find(currentPetId); if (petIdsItr != petIds.end()) // duplicate pets ROLLBACK(DUMP_FILE_BROKEN); uint32 newPetId = sObjectMgr->GeneratePetNumber(); petIds[currentPetId] = newPetId; if (!ChangeNth(line, 1, std::to_string(newPetId).c_str())) // character_pet.id update ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeNth(line, 3, newguid)) // character_pet.owner update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_PET_TABLE: // pet_aura, pet_spell, pet_spell_cooldown { std::string petIdStr = GetNth(line, 1); // lookup currpetid and match to new inserted pet id PetIds::const_iterator petIdsItr = petIds.find(atoul(petIdStr.c_str())); if (petIdsItr == petIds.end()) // couldn't find new inserted id ROLLBACK(DUMP_FILE_BROKEN); if (!ChangeNth(line, 1, std::to_string(petIdsItr->second).c_str())) ROLLBACK(DUMP_FILE_BROKEN); break; } default: TC_LOG_ERROR("misc", "Unknown dump table type: %u", type); break; } fixNULLfields(line); trans->Append(line.c_str()); } CharacterDatabase.CommitTransaction(trans); // in case of name conflict player has to rename at login anyway sWorld->AddCharacterInfo(ObjectGuid(HighGuid::Player, guid), account, name, gender, race, playerClass, level); sObjectMgr->GetGenerator<HighGuid::Item>().Set(sObjectMgr->GetGenerator<HighGuid::Item>().GetNextAfterMaxUsed() + items.size()); sObjectMgr->_mailId += mails.size(); if (incHighest) sObjectMgr->GetGenerator<HighGuid::Player>().Generate(); fclose(fin); return DUMP_SUCCESS; }