diff --git a/common/database.cpp b/common/database.cpp index c0193b927..a3405970d 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -1860,7 +1860,35 @@ bool Database::CopyCharacter( const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1); - std::vector tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" }; + // validate destination name doesn't exist already + const auto& destination_characters = CharacterDataRepository::GetWhere( + *this, + fmt::format( + "`name` = '{}' AND `deleted_at` IS NULL LIMIT 1", + Strings::Escape(destination_character_name) + ) + ); + if (!destination_characters.empty()) { + LogError("Character [{}] already exists", destination_character_name); + return false; + } + + std::vector tables_to_zero_id = { + "keyring", + "data_buckets", + "character_instance_safereturns", + "character_expedition_lockouts", + "character_instance_lockouts", + "character_parcels", + "character_tribute", + "player_titlesets", + }; + + std::vector ignore_tables = { + "guilds", + }; + + size_t total_rows_copied = 0; TransactionBegin(); @@ -1868,6 +1896,10 @@ bool Database::CopyCharacter( const std::string& table_name = t.first; const std::string& character_id_column_name = t.second; + if (Strings::Contains(ignore_tables, table_name)) { + continue; + } + auto results = QueryDatabase( fmt::format( "SHOW COLUMNS FROM {}", @@ -1918,6 +1950,10 @@ bool Database::CopyCharacter( value = std::to_string(destination_account_id); } + if (!Strings::IsNumber(value)) { + value = Strings::Escape(value); + } + new_values.emplace_back(value); } @@ -1950,6 +1986,11 @@ bool Database::CopyCharacter( ) ); + size_t rows_copied = insert_rows.size(); // Rows copied for this table + total_rows_copied += rows_copied; // Increment grand total + + LogInfo("Copying table [{}] rows [{}]", table_name, Strings::Commify(rows_copied)); + if (!insert.ErrorMessage().empty()) { TransactionRollback(); return false; @@ -1959,6 +2000,13 @@ bool Database::CopyCharacter( TransactionCommit(); + LogInfo( + "Character [{}] copied to [{}] total rows [{}]", + source_character_name, + destination_character_name, + Strings::Commify(total_rows_copied) + ); + return true; } diff --git a/world/cli/copy_character.cpp b/world/cli/copy_character.cpp index 7d915ad15..86c268217 100644 --- a/world/cli/copy_character.cpp +++ b/world/cli/copy_character.cpp @@ -12,12 +12,12 @@ void WorldserverCLI::CopyCharacter(int argc, char **argv, argh::parser &cmd, std }; std::vector options = {}; + EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv); + if (cmd[{"-h", "--help"}]) { return; } - EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv); - std::string source_character_name = cmd(2).str(); std::string destination_character_name = cmd(3).str(); std::string destination_account_name = cmd(4).str();