aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/auth_database.sql2
-rw-r--r--sql/updates/auth/master/2020_09_17_00_auth.sql3
-rw-r--r--sql/updates/world/master/2022_02_26_02_world_2020_09_17_00_world.sql5
-rw-r--r--src/server/game/Tools/PlayerDump.cpp48
-rw-r--r--src/server/game/Tools/PlayerDump.h10
-rw-r--r--src/server/scripts/Commands/cs_character.cpp93
6 files changed, 121 insertions, 40 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql
index b5886e1199a..37b2b8d6ee4 100644
--- a/sql/base/auth_database.sql
+++ b/sql/base/auth_database.sql
@@ -2176,6 +2176,7 @@ INSERT INTO `rbac_permissions` VALUES
(877,'Command: lookup quest id'),
(878,'Command: debug questreset'),
(879,'Command: debug poolstatus'),
+(880,'Command: pdump copy'),
(881,'Command: reload vehicle_template'),
(882,'Command: reload spell_script_names');
/*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */;
@@ -2487,6 +2488,7 @@ INSERT INTO `updates` VALUES
('2020_08_14_00_auth.sql','DFB9B07A7846FC0E124EE4CC099E49FE5742FB66','ARCHIVED','2020-08-14 21:41:24',0),
('2020_08_26_00_auth.sql','D5EF787DECB41D898379588F101A0453B46F04D9','ARCHIVED','2020-08-26 21:00:34',0),
('2020_09_06_00_auth.sql','DC4B5D4C65EB138D5609F137799C3289B9CC2493','ARCHIVED','2020-09-06 00:00:00',0),
+('2020_09_17_00_auth.sql','BBC0A8B2BBED38A57A83999909EB066753A893C5','ARCHIVED','2020-09-17 00:00:00',0),
('2020_09_25_00_auth.sql','3CCA78EF89223724BA6784A4F3783DED30416637','ARCHIVED','2020-09-25 19:52:40',0),
('2020_10_20_00_auth.sql','1835C5EFD5816DEF914F27E867C8C8D5E08B3F68','ARCHIVED','2020-10-20 21:36:49',0),
('2020_12_06_00_auth.sql','FA254400D3D7D53E9C350EABFEABFF4EC3AD40DA','ARCHIVED','2020-12-06 20:25:10',0),
diff --git a/sql/updates/auth/master/2020_09_17_00_auth.sql b/sql/updates/auth/master/2020_09_17_00_auth.sql
new file mode 100644
index 00000000000..9cc01ed837e
--- /dev/null
+++ b/sql/updates/auth/master/2020_09_17_00_auth.sql
@@ -0,0 +1,3 @@
+--
+DELETE FROM `rbac_permissions` WHERE `id`= 880;
+INSERT INTO `rbac_permissions` (`id`,`name`) VALUES (880, 'Command: pdump copy');
diff --git a/sql/updates/world/master/2022_02_26_02_world_2020_09_17_00_world.sql b/sql/updates/world/master/2022_02_26_02_world_2020_09_17_00_world.sql
new file mode 100644
index 00000000000..96180f587f1
--- /dev/null
+++ b/sql/updates/world/master/2022_02_26_02_world_2020_09_17_00_world.sql
@@ -0,0 +1,5 @@
+--
+DELETE FROM `command` WHERE `name`='pdump copy';
+INSERT INTO `command` (`name`,`permission`,`help`) VALUES
+('pdump copy',880,'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.');
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);