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
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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";