feat(Core/DBC): Implement NamesProfanity and NamesReserved DBC (#14956)

This commit is contained in:
Kitzunu
2023-02-12 10:51:42 +01:00
committed by GitHub
parent 1d414a35ba
commit 5a9aeada12
11 changed files with 187 additions and 27 deletions

View File

@@ -0,0 +1,16 @@
--
DROP TABLE IF EXISTS `namesreserved_dbc`;
CREATE TABLE `namesreserved_dbc` (
`ID` INT UNSIGNED NOT NULL,
`Pattern` TINYTEXT NOT NULL,
`LanguagueID` TINYINT NOT NULL,
PRIMARY KEY (`ID`)
);
DROP TABLE IF EXISTS `namesprofanity_dbc`;
CREATE TABLE `namesprofanity_dbc` (
`ID` INT UNSIGNED NOT NULL,
`Pattern` TINYTEXT NOT NULL,
`LanguagueID` TINYINT NOT NULL,
PRIMARY KEY (`ID`)
);

View File

@@ -626,6 +626,24 @@ RealmZone = 1
World.RealmAvailability = 1
#
# StrictNames.Reserved
# Description: Use the Reserved Filter from DBC.
# Prevents Player, Pet & Charter names from containing reserved names.
# Default: 1 - Enabled
# 0 - Disabled
StrictNames.Reserved = 1
#
# StrictNames.Profanity
# Description: Use the Profanity Filter from DBC.
# Prevents Player, Pet & Charter names from containing profanity.
# Default: 1 - Enabled
# 0 - Disabled
StrictNames.Profanity = 1
#
# StrictPlayerNames
# Description: Limit player name to language specific symbol set. Prevents character

View File

@@ -121,6 +121,9 @@ MapDifficultyMap sMapDifficultyMap;
DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
DBCStorage <NamesReservedEntry> sNamesReservedStore(NamesReservedfmt);
DBCStorage <NamesProfanityEntry> sNamesProfanityStore(NamesProfanityfmt);
DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore(OverrideSpellDatafmt);
DBCStorage <PowerDisplayEntry> sPowerDisplayStore(PowerDisplayfmt);
@@ -330,6 +333,8 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sMapStore, "Map.dbc", "map_dbc");
LOAD_DBC(sMapDifficultyStore, "MapDifficulty.dbc", "mapdifficulty_dbc");
LOAD_DBC(sMovieStore, "Movie.dbc", "movie_dbc");
LOAD_DBC(sNamesReservedStore, "NamesReserved.dbc", "namesreserved_dbc");
LOAD_DBC(sNamesProfanityStore, "NamesProfanity.dbc", "namesprofanity_dbc");
LOAD_DBC(sOverrideSpellDataStore, "OverrideSpellData.dbc", "overridespelldata_dbc");
LOAD_DBC(sPowerDisplayStore, "PowerDisplay.dbc", "powerdisplay_dbc");
LOAD_DBC(sPvPDifficultyStore, "PvpDifficulty.dbc", "pvpdifficulty_dbc");

View File

@@ -138,6 +138,8 @@ extern DBCStorage <MapEntry> sMapStore;
//extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed
extern MapDifficultyMap sMapDifficultyMap;
extern DBCStorage <MovieEntry> sMovieStore;
extern DBCStorage <NamesReservedEntry> sNamesReservedStore;
extern DBCStorage <NamesProfanityEntry> sNamesProfanityStore;
extern DBCStorage <OverrideSpellDataEntry> sOverrideSpellDataStore;
extern DBCStorage <PowerDisplayEntry> sPowerDisplayStore;
extern DBCStorage <QuestSortEntry> sQuestSortStore;

View File

@@ -26,6 +26,7 @@
#include "Config.h"
#include "Containers.h"
#include "DatabaseEnv.h"
#include "DBCStructure.h"
#include "DisableMgr.h"
#include "GameObjectAIFactory.h"
#include "GameEventMgr.h"
@@ -53,6 +54,7 @@
#include "World.h"
#include "StringConvert.h"
#include "Tokenize.h"
#include <boost/algorithm/string.hpp>
ScriptMapMap sSpellScripts;
ScriptMapMap sEventScripts;
@@ -203,6 +205,62 @@ std::string ScriptInfo::GetDebugInfo() const
return std::string(sz);
}
/**
* @name ReservedNames
* @brief Checks NamesReserved.dbc for reserved names
*
* @param name Name to check for match in NamesReserved.dbc
* @return true/false
*/
bool ReservedNames(std::wstring& name)
{
for (NamesReservedEntry const* reservedStore : sNamesReservedStore)
{
std::wstring PatternString;
Utf8toWStr(reservedStore->Pattern, PatternString);
boost::algorithm::replace_all(PatternString, "\\<", "");
boost::algorithm::replace_all(PatternString, "\\>", "");
int stringCompare = name.compare(PatternString);
if (stringCompare == 0)
{
return true;
}
}
return false;
};
/**
* @name ProfanityNames
* @brief Checks NamesProfanity.dbc for reserved names
*
* @param name Name to check for match in NamesProfanity.dbc
* @return true/false
*/
bool ProfanityNames(std::wstring& name)
{
for (NamesProfanityEntry const* profanityStore : sNamesProfanityStore)
{
std::wstring PatternString;
Utf8toWStr(profanityStore->Pattern, PatternString);
boost::algorithm::replace_all(PatternString, "\\<", "");
boost::algorithm::replace_all(PatternString, "\\>", "");
int stringCompare = name.compare(PatternString);
if (stringCompare == 0)
{
return true;
}
}
return false;
}
bool normalizePlayerName(std::string& name)
{
if (name.empty())
@@ -8222,25 +8280,55 @@ bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bo
uint8 ObjectMgr::CheckPlayerName(std::string_view name, bool create)
{
std::wstring wname;
// Check for invalid characters
if (!Utf8toWStr(name, wname))
return CHAR_NAME_INVALID_CHARACTER;
// Check for too long name
if (wname.size() > MAX_PLAYER_NAME)
return CHAR_NAME_TOO_LONG;
// Check for too short name
uint32 minName = sWorld->getIntConfig(CONFIG_MIN_PLAYER_NAME);
if (wname.size() < minName)
return CHAR_NAME_TOO_SHORT;
// Check for mixed languages
uint32 strictMask = sWorld->getIntConfig(CONFIG_STRICT_PLAYER_NAMES);
if (!isValidString(wname, strictMask, false, create))
return CHAR_NAME_MIXED_LANGUAGES;
// Check for three consecutive letters
wstrToLower(wname);
for (size_t i = 2; i < wname.size(); ++i)
if (wname[i] == wname[i - 1] && wname[i] == wname[i - 2])
return CHAR_NAME_THREE_CONSECUTIVE;
// Check Reserved Name from Database
if (sObjectMgr->IsReservedName(name))
{
return CHAR_NAME_RESERVED;
}
// Check for Reserved Name from DBC
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_RESERVED))
{
if (ReservedNames(wname))
{
return CHAR_NAME_RESERVED;
}
}
// Check for Profanity
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_PROFANITY))
{
if (ProfanityNames(wname))
{
return CHAR_NAME_PROFANE;
}
}
return CHAR_NAME_SUCCESS;
}
@@ -8257,6 +8345,24 @@ bool ObjectMgr::IsValidCharterName(std::string_view name)
if (wname.size() < minName)
return false;
// Check for Reserved Name from DBC
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_RESERVED))
{
if (ReservedNames(wname))
{
return false;
}
}
// Check for Profanity
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_PROFANITY))
{
if (ProfanityNames(wname))
{
return false;
}
}
uint32 strictMask = sWorld->getIntConfig(CONFIG_STRICT_CHARTER_NAMES);
return isValidString(wname, strictMask, true);
@@ -8293,6 +8399,24 @@ PetNameInvalidReason ObjectMgr::CheckPetName(std::string_view name)
if (!isValidString(wname, strictMask, false))
return PET_NAME_MIXED_LANGUAGES;
// Check for Reserved Name from DBC
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_RESERVED))
{
if (ReservedNames(wname))
{
return PET_NAME_RESERVED;
}
}
// Check for Profanity
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_PROFANITY))
{
if (ProfanityNames(wname))
{
return PET_NAME_PROFANE;
}
}
return PET_NAME_SUCCESS;
}

View File

@@ -691,6 +691,8 @@ SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const* rcEntry);
#define MAX_CHARTER_NAME 24 // max allowed by client name length
#define MAX_CHANNEL_NAME 50 // pussywizard
bool ReservedNames(std::wstring& name);
bool ProfanityNames(std::wstring& name);
bool normalizePlayerName(std::string& name);
struct LanguageDesc

View File

@@ -356,12 +356,6 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
return;
}
if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(createInfo->Name))
{
SendCharCreate(CHAR_NAME_RESERVED);
return;
}
// speedup check for heroic class disabled case
uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM);
if (heroic_free_slots == 0 && AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT)
@@ -1351,13 +1345,6 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData)
return;
}
// check name limitations
if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(renameInfo->Name))
{
SendCharRename(CHAR_NAME_RESERVED, renameInfo.get());
return;
}
// Ensure that the character belongs to the current account, that rename at login is enabled
// and that there is no character with the desired new name
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_FREE_NAME);
@@ -1698,13 +1685,6 @@ void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<CharacterCustomiz
return;
}
// check name limitations
if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(customizeInfo->Name))
{
SendCharCustomize(CHAR_NAME_RESERVED, customizeInfo.get());
return;
}
// character with this name already exist
if (ObjectGuid newguid = sCharacterCache->GetCharacterGuidByName(customizeInfo->Name))
{
@@ -2083,13 +2063,6 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact
return;
}
// check name limitations
if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(factionChangeInfo->Name))
{
SendCharFactionChange(CHAR_NAME_RESERVED, factionChangeInfo.get());
return;
}
// character with this name already exist
if (ObjectGuid newguid = sCharacterCache->GetCharacterGuidByName(factionChangeInfo->Name))
{

View File

@@ -179,6 +179,8 @@ enum WorldBoolConfigs
CONFIG_OBJECT_SPARKLES,
CONFIG_LOW_LEVEL_REGEN_BOOST,
CONFIG_OBJECT_QUEST_MARKERS,
CONFIG_STRICT_NAMES_RESERVED,
CONFIG_STRICT_NAMES_PROFANITY,
CONFIG_ALLOWS_RANK_MOD_FOR_PET_HEALTH,
BOOL_CONFIG_VALUE_COUNT
};

View File

@@ -718,6 +718,8 @@ void World::LoadConfigSettings(bool reload)
else
_int_configs[CONFIG_REALM_ZONE] = sConfigMgr->GetOption<int32>("RealmZone", REALM_ZONE_DEVELOPMENT);
_bool_configs[CONFIG_STRICT_NAMES_RESERVED] = sConfigMgr->GetOption<bool> ("StrictNames.Reserved", true);
_bool_configs[CONFIG_STRICT_NAMES_PROFANITY] = sConfigMgr->GetOption<bool> ("StrictNames.Profanity", true);
_int_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfigMgr->GetOption<int32> ("StrictPlayerNames", 0);
_int_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfigMgr->GetOption<int32> ("StrictCharterNames", 0);
_int_configs[CONFIG_STRICT_CHANNEL_NAMES] = sConfigMgr->GetOption<int32> ("StrictChannelNames", 0);

View File

@@ -1377,6 +1377,20 @@ struct MovieEntry
//uint32 unk2; // 2 always 100
};
struct NamesReservedEntry
{
//uint32 ID; // 0
char const* Pattern; // 1
//uint32 Language; // 2
};
struct NamesProfanityEntry
{
//uint32 ID; // 0
char const* Pattern; // 1
//uint32 Language; // 2
};
#define MAX_OVERRIDE_SPELL 10
struct OverrideSpellDataEntry

View File

@@ -84,6 +84,8 @@ char constexpr MailTemplateEntryfmt[] = "nxxxxxxxxxxxxxxxxxssssssssssssssssx";
char constexpr MapEntryfmt[] = "nxiixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxiii";
char constexpr MapDifficultyEntryfmt[] = "diisxxxxxxxxxxxxxxxxiix";
char constexpr MovieEntryfmt[] = "nxx";
char constexpr NamesReservedfmt[] = "xsx";
char constexpr NamesProfanityfmt[] = "xsx";
char constexpr OverrideSpellDatafmt[] = "niiiiiiiiiix";
char constexpr PowerDisplayfmt[] = "nixxxx";
char constexpr QuestSortEntryfmt[] = "nxxxxxxxxxxxxxxxxx";