diff options
author | Giacomo Pozzoni <giacomopoz@gmail.com> | 2020-09-17 21:49:52 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-17 21:49:52 +0200 |
commit | 6215da0d640bd86a7c2bc144859c1542f09fc1a6 (patch) | |
tree | a2100843e1442efd46a32594320ad121393ce810 /src | |
parent | d2f51569d12f3cb72e53351914d2535eb6ef2dbe (diff) |
Script/Commands: Add ".pdump copy" command (#25455)
* Script/Commands: Add ".pdump copy" command
Syntax: .pdump copy $playerNameOrGUID $account [$newname] [$newguid]
Copy character with name/guid $playerNameOrGUID into character list of $account with $newname, with first free or $newguid guid.
* Add missing return
* Restore eof check
* Fix sql
* Use forward declaration header
Co-authored-by: Shauren <shauren.trinity@gmail.com>
* Remove buffer when reading a line
* Rename sql files
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 1 | ||||
-rw-r--r-- | src/server/game/Tools/PlayerDump.cpp | 49 | ||||
-rw-r--r-- | src/server/game/Tools/PlayerDump.h | 10 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_character.cpp | 93 |
4 files changed, 113 insertions, 40 deletions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 64a61b70bc3..8b15c9a3310 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -781,6 +781,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_LOOKUP_QUEST_ID = 877, RBAC_PERM_COMMAND_DEBUG_QUESTRESET = 878, RBAC_PERM_COMMAND_DEBUG_POOLSTATUS = 879, + RBAC_PERM_COMMAND_PDUMP_COPY = 880, // // IF YOU ADD NEW PERMISSIONS, ADD THEM IN MASTER BRANCH AS WELL! // diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 7bc573b11c0..3e603bc6d44 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -24,6 +24,8 @@ #include "ObjectMgr.h" #include "Player.h" #include "World.h" +#include <fstream> +#include <sstream> // static data enum GuidType : uint8 @@ -712,7 +714,7 @@ bool PlayerDumpWriter::GetDump(ObjectGuid::LowType guid, std::string& dump) return true; } -DumpReturn PlayerDumpWriter::WriteDump(std::string const& file, ObjectGuid::LowType guid) +DumpReturn PlayerDumpWriter::WriteDumpToFile(std::string const& file, ObjectGuid::LowType guid) { if (sWorld->getBoolConfig(CONFIG_PDUMP_NO_PATHS)) if (strchr(file.c_str(), '\\') || strchr(file.c_str(), '/')) @@ -738,6 +740,14 @@ DumpReturn PlayerDumpWriter::WriteDump(std::string const& file, ObjectGuid::LowT return ret; } +DumpReturn PlayerDumpWriter::WriteDumpToString(std::string& dump, ObjectGuid::LowType guid) +{ + DumpReturn ret = DUMP_SUCCESS; + if (!GetDump(guid, dump)) + ret = DUMP_CHARACTER_DELETED; + return ret; +} + // Reading - High-level functions inline void FixNULLfields(std::string& line) { @@ -750,16 +760,12 @@ inline void FixNULLfields(std::string& line) } } -DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, std::string name, ObjectGuid::LowType guid) +DumpReturn PlayerDumpReader::LoadDump(std::istream& input, uint32 account, std::string name, ObjectGuid::LowType guid) { uint32 charcount = AccountMgr::GetCharactersCount(account); if (charcount >= 10) return DUMP_TOO_MANY_CHARS; - FileHandle fin = GetFileHandle(file.c_str(), "r"); - if (!fin) - return DUMP_FILE_OPEN_ERROR; - std::string newguid, chraccount; // make sure the same guid doesn't already exist and is safe to use @@ -808,8 +814,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s std::map<uint64, uint64> equipmentSetIds; uint64 equipmentSetGuidOffset = sObjectMgr->_equipmentSetGuid; - static size_t const BUFFER_SIZE = 32000; - char buf[BUFFER_SIZE] = { }; + std::string line; uint8 gender = GENDER_NONE; uint8 race = RACE_NONE; @@ -820,17 +825,8 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s size_t lineNumber = 0; CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - while (!feof(fin.get())) + while (std::getline(input, line)) { - if (!fgets(buf, BUFFER_SIZE, fin.get())) - { - if (feof(fin.get())) - break; - return DUMP_FILE_BROKEN; - } - - std::string line; - line.assign(buf); ++lineNumber; // skip empty strings @@ -950,6 +946,9 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s trans->Append(line.c_str()); } + if (input.fail() && !input.eof()) + return DUMP_FILE_BROKEN; + CharacterDatabase.CommitTransaction(trans); // in case of name conflict player has to rename at login anyway @@ -967,3 +966,17 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s return DUMP_SUCCESS; } + +DumpReturn PlayerDumpReader::LoadDumpFromString(std::string const& dump, uint32 account, std::string name, ObjectGuid::LowType guid) +{ + std::istringstream input(dump); + return LoadDump(input, account, name, guid); +} + +DumpReturn PlayerDumpReader::LoadDumpFromFile(std::string const& file, uint32 account, std::string name, ObjectGuid::LowType guid) +{ + std::ifstream input(file); + if (!input) + return DUMP_FILE_OPEN_ERROR; + return LoadDump(input, account, name, guid); +} diff --git a/src/server/game/Tools/PlayerDump.h b/src/server/game/Tools/PlayerDump.h index 578d663f76e..5f9b9df54dc 100644 --- a/src/server/game/Tools/PlayerDump.h +++ b/src/server/game/Tools/PlayerDump.h @@ -19,6 +19,7 @@ #define _PLAYER_DUMP_H #include <string> +#include <iosfwd> #include <map> #include <set> #include "ObjectGuid.h" @@ -79,7 +80,8 @@ class TC_GAME_API PlayerDumpWriter : public PlayerDump PlayerDumpWriter() { } bool GetDump(ObjectGuid::LowType guid, std::string& dump); - DumpReturn WriteDump(std::string const& file, ObjectGuid::LowType guid); + DumpReturn WriteDumpToFile(std::string const& file, ObjectGuid::LowType guid); + DumpReturn WriteDumpToString(std::string& dump, ObjectGuid::LowType guid); private: bool AppendTable(StringTransaction& trans, ObjectGuid::LowType guid, TableStruct const& tableStruct, DumpTable const& dumpTable); @@ -97,7 +99,11 @@ class TC_GAME_API PlayerDumpReader : public PlayerDump public: PlayerDumpReader() { } - DumpReturn LoadDump(std::string const& file, uint32 account, std::string name, ObjectGuid::LowType guid); + DumpReturn LoadDumpFromFile(std::string const& file, uint32 account, std::string name, ObjectGuid::LowType guid); + DumpReturn LoadDumpFromString(std::string const& dump, uint32 account, std::string name, ObjectGuid::LowType guid); + + private: + DumpReturn LoadDump(std::istream& input, uint32 account, std::string name, ObjectGuid::LowType guid); }; #endif diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 52dbfb0424f..c8c374b5f21 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -47,6 +47,7 @@ public: { static std::vector<ChatCommand> pdumpCommandTable = { + { "copy", rbac::RBAC_PERM_COMMAND_PDUMP_COPY, true, &HandlePDumpCopyCommand, "" }, { "load", rbac::RBAC_PERM_COMMAND_PDUMP_LOAD, true, &HandlePDumpLoadCommand, "" }, { "write", rbac::RBAC_PERM_COMMAND_PDUMP_WRITE, true, &HandlePDumpWriteCommand, "" }, }; @@ -779,39 +780,57 @@ public: return true; } - static bool HandlePDumpLoadCommand(ChatHandler* handler, std::string fileName, AccountIdentifier account, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID) + static bool HandlePDumpCopyCommand(ChatHandler* handler, PlayerIdentifier player, AccountIdentifier account, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID) { std::string name; - if (characterName) + if (!ValidatePDumpTarget(handler, name, characterName, characterGUID)) + return false; + + std::string dump; + switch (PlayerDumpWriter().WriteDumpToString(dump, player.GetGUID().GetCounter())) { - name.assign(*characterName); - // normalize the name if specified and check if it exists - if (!normalizePlayerName(name)) - { - handler->PSendSysMessage(LANG_INVALID_CHARACTER_NAME); + case DUMP_SUCCESS: + break; + case DUMP_CHARACTER_DELETED: + handler->PSendSysMessage(LANG_COMMAND_EXPORT_DELETED_CHAR); handler->SetSentErrorMessage(true); return false; - } - - if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS) - { - handler->PSendSysMessage(LANG_INVALID_CHARACTER_NAME); + case DUMP_FILE_OPEN_ERROR: // this error code should not happen + default: + handler->PSendSysMessage(LANG_COMMAND_EXPORT_FAILED); handler->SetSentErrorMessage(true); return false; - } } - if (characterGUID) + switch (PlayerDumpReader().LoadDumpFromString(dump, account, name, characterGUID.value_or(0))) { - if (sCharacterCache->GetCharacterCacheByGuid(ObjectGuid(HighGuid::Player, *characterGUID))) - { - handler->PSendSysMessage(LANG_CHARACTER_GUID_IN_USE, *characterGUID); + case DUMP_SUCCESS: + break; + case DUMP_TOO_MANY_CHARS: + handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, account.GetName().c_str(), account.GetID()); + handler->SetSentErrorMessage(true); + return false; + case DUMP_FILE_OPEN_ERROR: // this error code should not happen + case DUMP_FILE_BROKEN: // this error code should not happen + default: + handler->PSendSysMessage(LANG_COMMAND_IMPORT_FAILED); handler->SetSentErrorMessage(true); return false; - } } - switch (PlayerDumpReader().LoadDump(fileName, account, name, characterGUID.value_or(0))) + // ToDo: use a new trinity_string for this commands + handler->PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); + + return true; + } + + static bool HandlePDumpLoadCommand(ChatHandler* handler, std::string fileName, AccountIdentifier account, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID) + { + std::string name; + if (!ValidatePDumpTarget(handler, name, characterName, characterGUID)) + return false; + + switch (PlayerDumpReader().LoadDumpFromFile(fileName, account, name, characterGUID.value_or(0))) { case DUMP_SUCCESS: handler->PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); @@ -837,9 +856,43 @@ public: return true; } + static bool ValidatePDumpTarget(ChatHandler* handler, std::string& name, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID) + { + if (characterName) + { + name.assign(*characterName); + // normalize the name if specified and check if it exists + if (!normalizePlayerName(name)) + { + handler->PSendSysMessage(LANG_INVALID_CHARACTER_NAME); + handler->SetSentErrorMessage(true); + return false; + } + + if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS) + { + handler->PSendSysMessage(LANG_INVALID_CHARACTER_NAME); + handler->SetSentErrorMessage(true); + return false; + } + } + + if (characterGUID) + { + if (sCharacterCache->GetCharacterCacheByGuid(ObjectGuid(HighGuid::Player, *characterGUID))) + { + handler->PSendSysMessage(LANG_CHARACTER_GUID_IN_USE, *characterGUID); + handler->SetSentErrorMessage(true); + return false; + } + } + + return true; + } + static bool HandlePDumpWriteCommand(ChatHandler* handler, std::string fileName, PlayerIdentifier player) { - switch (PlayerDumpWriter().WriteDump(fileName, player.GetGUID().GetCounter())) + switch (PlayerDumpWriter().WriteDumpToFile(fileName, player.GetGUID().GetCounter())) { case DUMP_SUCCESS: handler->PSendSysMessage(LANG_COMMAND_EXPORT_SUCCESS); |