diff options
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/game/Tools/PlayerDump.cpp | 48 | ||||
| -rw-r--r-- | src/server/game/Tools/PlayerDump.h | 10 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_character.cpp | 93 | 
3 files changed, 111 insertions, 40 deletions
diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index b37cb909b0d..a818c38dc58 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -25,6 +25,7 @@  #include "Player.h"  #include "World.h"  #include <boost/algorithm/string/find.hpp> +#include <fstream>  #include <sstream>  // static data @@ -809,7 +810,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(), '/')) @@ -835,6 +836,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)  { @@ -847,16 +856,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 >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))          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 @@ -905,8 +910,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; @@ -917,17 +921,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 @@ -1047,6 +1042,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 @@ -1064,3 +1062,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 91c6741dc29..7858acff731 100644 --- a/src/server/game/Tools/PlayerDump.h +++ b/src/server/game/Tools/PlayerDump.h @@ -20,6 +20,7 @@  #include "ObjectGuid.h"  #include <string> +#include <iosfwd>  #include <set>  enum DumpTableType @@ -90,7 +91,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); @@ -108,7 +110,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 a604764c667..4a6d872886f 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -48,6 +48,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,              "" },          }; @@ -776,39 +777,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::Create<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); @@ -834,9 +853,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::Create<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);  | 
