Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-01-31 18:29:34 +08:00
38 changed files with 671 additions and 278 deletions
@@ -42,7 +42,6 @@ void AutobroadcastMgr::LoadAutobroadcasts()
if (!result)
{
LOG_WARN("autobroadcast", ">> Loaded 0 autobroadcasts definitions. DB table `autobroadcast` is empty for this realm!");
LOG_INFO("autobroadcast", " ");
return;
}
@@ -54,35 +53,66 @@ void AutobroadcastMgr::LoadAutobroadcasts()
_announceType = AnnounceType::World;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint8 textId = fields[0].Get<uint8>();
ObjectMgr::AddLocaleString(fields[2].Get<std::string>(), DEFAULT_LOCALE, _autobroadcasts[textId]);
_autobroadcastsWeights[textId] = fields[1].Get<uint8>();
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} Autobroadcast Definitions in {} ms", _autobroadcasts.size(), GetMSTimeDiffToNow(oldMSTime));
}
void AutobroadcastMgr::LoadAutobroadcastsLocalized()
{
uint32 oldMSTime = getMSTime();
uint32 realmId = sConfigMgr->GetOption<int32>("RealmID", 0);
if (_autobroadcasts.empty())
return;
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST_LOCALIZED);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 localized autobroadcasts definitions. DB table `autobroadcast_localized` is empty for this realm!");
LOG_INFO("server.loading", " ");
return;
}
uint8 count = 0;
do
{
Field* fields = result->Fetch();
uint8 id = fields[0].Get<uint8>();
uint8 textId = fields[0].Get<uint8>();
LocaleConstant locale = GetLocaleByName(fields[1].Get<std::string>());
_autobroadcasts[id] = fields[2].Get<std::string>();
_autobroadcastsWeights[id] = fields[1].Get<uint8>();
if (locale == DEFAULT_LOCALE || ObjectMgr::GetLocaleString(_autobroadcasts[textId], DEFAULT_LOCALE).empty())
continue;
++count;
ObjectMgr::AddLocaleString(fields[2].Get<std::string>(), locale, _autobroadcasts[textId]);
count++;
} while (result->NextRow());
LOG_INFO("autobroadcast", ">> Loaded {} Autobroadcast Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("autobroadcast", " ");
LOG_INFO("server.loading", ">> Loaded {} Localized Autobroadcast Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
void AutobroadcastMgr::SendAutobroadcasts()
{
if (_autobroadcasts.empty())
{
return;
}
uint32 weight = 0;
uint8 textId = 0;
AutobroadcastsWeightMap selectionWeights;
std::string msg;
for (AutobroadcastsWeightMap::const_iterator it = _autobroadcastsWeights.begin(); it != _autobroadcastsWeights.end(); ++it)
{
if (it->second)
@@ -101,42 +131,78 @@ void AutobroadcastMgr::SendAutobroadcasts()
weight += it->second;
if (selectedWeight < weight)
{
msg = _autobroadcasts[it->first];
textId = it->first;
break;
}
}
}
else
{
msg = _autobroadcasts[urand(0, _autobroadcasts.size())];
textId = urand(0, _autobroadcasts.size());
}
switch (_announceType)
{
case AnnounceType::World:
SendWorldAnnouncement(msg);
SendWorldAnnouncement(textId);
break;
case AnnounceType::Notification:
SendNotificationAnnouncement(msg);
SendNotificationAnnouncement(textId);
break;
case AnnounceType::Both:
SendWorldAnnouncement(msg);
SendNotificationAnnouncement(msg);
SendWorldAnnouncement(textId);
SendNotificationAnnouncement(textId);
default:
break;
}
LOG_DEBUG("autobroadcast", "AutobroadcastMgr::SendAutobroadcasts: '{}'", msg);
LOG_DEBUG("autobroadcast", "AutobroadcastMgr::SendAutobroadcasts: '{}'", textId);
}
void AutobroadcastMgr::SendWorldAnnouncement(std::string msg)
void AutobroadcastMgr::SendWorldAnnouncement(uint8 textId)
{
ChatHandler(nullptr).SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.data());
// Send localized messages to all sessions
ChatHandler(nullptr).DoForAllValidSessions([&](Player* player)
{
// Get player's locale
LocaleConstant locale = player->GetSession()->GetSessionDbLocaleIndex();
if (!_autobroadcasts.empty())
return;
std::string_view localizedMessage = ObjectMgr::GetLocaleString(_autobroadcasts[textId], locale);
// Check if there is a localized message if not use default one.
if (localizedMessage.empty())
localizedMessage = ObjectMgr::GetLocaleString(_autobroadcasts[textId], DEFAULT_LOCALE);
// Send the localized or fallback message
ChatHandler(player->GetSession()).SendWorldTextOptional(localizedMessage, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST);
});
}
void AutobroadcastMgr::SendNotificationAnnouncement(std::string msg)
void AutobroadcastMgr::SendNotificationAnnouncement(uint8 textId)
{
WorldPacket data(SMSG_NOTIFICATION, (msg.size() + 1));
data << msg.data();
sWorld->SendGlobalMessage(&data);
ChatHandler(nullptr).DoForAllValidSessions([&](Player* player)
{
// Retrieve player's locale
LocaleConstant locale = player->GetSession()->GetSessionDbLocaleIndex();
if (!_autobroadcasts.count(textId))
return;
// Get localized message
std::string_view localizedMessage = ObjectMgr::GetLocaleString(_autobroadcasts[textId], locale);
// Check if there is a localized message if not use default one.
if (localizedMessage.empty())
localizedMessage = ObjectMgr::GetLocaleString(_autobroadcasts[textId], DEFAULT_LOCALE);
// Prepare the WorldPacket
WorldPacket data(SMSG_NOTIFICATION, (localizedMessage.size() + 1));
data << localizedMessage;
// Send packet to the player
player->GetSession()->SendPacket(&data);
});
}
@@ -20,6 +20,7 @@
#include "Common.h"
#include <map>
#include <vector>
enum class AnnounceType : uint8
{
@@ -34,17 +35,18 @@ public:
static AutobroadcastMgr* instance();
void LoadAutobroadcasts();
void LoadAutobroadcastsLocalized();
void SendAutobroadcasts();
private:
void SendWorldAnnouncement(std::string msg);
void SendNotificationAnnouncement(std::string msg);
void SendWorldAnnouncement(uint8 textId);
void SendNotificationAnnouncement(uint8 textId);
typedef std::map<uint8, std::string> AutobroadcastsMap;
typedef std::map<uint8, std::vector<std::string>> AutobroadcastsMap;
typedef std::map<uint8, uint8> AutobroadcastsWeightMap;
AutobroadcastsMap _autobroadcasts;
AutobroadcastsWeightMap _autobroadcastsWeights;
AutobroadcastsMap _autobroadcasts; // autobroadcast messages
AutobroadcastsWeightMap _autobroadcastsWeights; // Weights for each message
AnnounceType _announceType;
};
+18 -1
View File
@@ -273,7 +273,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_lastLeashExtensionTime(nullptr), m_cannotReachTimer(0),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f),_sparringPct(0.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_lastLeashExtensionTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
@@ -608,6 +608,8 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
SetCanModifyStats(true);
UpdateAllStats();
LoadSparringPct();
// checked and error show at loading templates
if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction))
{
@@ -1189,6 +1191,7 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u
}
LoadCreaturesAddon();
LoadSparringPct();
//! Need to be called after LoadCreaturesAddon - MOVEMENTFLAG_HOVER is set there
m_positionZ += GetHoverHeight();
@@ -2025,6 +2028,8 @@ void Creature::setDeathState(DeathState state, bool despawn)
Motion_Initialize();
LoadCreaturesAddon(true);
LoadSparringPct();
if (GetCreatureData() && GetPhaseMask() != GetCreatureData()->phaseMask)
SetPhaseMask(GetCreatureData()->phaseMask, false);
}
@@ -2798,6 +2803,18 @@ bool Creature::LoadCreaturesAddon(bool reload)
return true;
}
void Creature::LoadSparringPct()
{
ObjectGuid::LowType spawnId = GetSpawnId();
auto const& sparringData = sObjectMgr->GetSparringData();
auto itr = sparringData.find(spawnId);
if (itr != sparringData.end() && !itr->second.empty())
{
_sparringPct = itr->second[0];
}
}
/// Send a message to LocalDefense channel for players opposition team in the zone
void Creature::SendZoneUnderAttackMessage(Player* attacker)
{
@@ -187,6 +187,9 @@ public:
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage, uint8 damageIndex) override;
void LoadSparringPct();
[[nodiscard]] float GetSparringPct() const { return _sparringPct; }
bool HasWeapon(WeaponAttackType type) const override;
bool HasWeaponForAttack(WeaponAttackType type) const override { return (Unit::HasWeaponForAttack(type) && HasWeapon(type)); }
void SetCanDualWield(bool value) override;
@@ -483,6 +486,8 @@ protected:
float m_detectionDistance;
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
float _sparringPct;
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;
bool CanAlwaysSee(WorldObject const* obj) const override;
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
+33
View File
@@ -1032,6 +1032,17 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
}
}
// Sparring
if (victim->CanSparringWith(attacker))
{
if (damage >= victim->GetHealth())
damage = 0;
uint32 sparringHealth = victim->GetHealth() * (victim->ToCreature()->GetSparringPct() / 100);
if (victim->GetHealth() - damage <= sparringHealth)
damage = 0;
}
if (health <= damage)
{
LOG_DEBUG("entities.unit", "DealDamage: victim just died");
@@ -2635,6 +2646,10 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_A
Unit::DealDamageMods(victim, damageInfo.damages[i].damage, &damageInfo.damages[i].absorb);
}
// Related to sparring system. Allow attack animations even if there are no damages
if (victim->CanSparringWith(damageInfo.attacker))
damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
SendAttackStateUpdate(&damageInfo);
//TriggerAurasProcOnEvent(damageInfo);
@@ -3954,6 +3969,24 @@ void Unit::_UpdateAutoRepeatSpell()
}
}
bool Unit::CanSparringWith(Unit const* attacker) const
{
if (!IsCreature() || IsCharmedOwnedByPlayerOrPlayer())
return false;
if (!attacker)
return false;
if (!attacker->IsCreature() || attacker->IsCharmedOwnedByPlayerOrPlayer())
return false;
if (Creature const* creature = ToCreature())
if (!creature->GetSparringPct())
return false;
return true;
}
void Unit::SetCurrentCastedSpell(Spell* pSpell)
{
ASSERT(pSpell); // nullptr may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
+5
View File
@@ -726,6 +726,9 @@ public:
void RemoveUnitFlag2(UnitFlags2 flags) { RemoveFlag(UNIT_FIELD_FLAGS_2, flags); }
void ReplaceAllUnitFlags2(UnitFlags2 flags) { SetUInt32Value(UNIT_FIELD_FLAGS_2, flags); }
void SetEmoteState(Emote emoteState) { SetUInt32Value(UNIT_NPC_EMOTESTATE, emoteState); } /// @brief Sets emote state (looping emote). Emotes available in SharedDefines.h
void ClearEmoteState() { SetEmoteState(EMOTE_ONESHOT_NONE); } /// @brief Clears emote state (looping emote)
// NPC flags
NPCFlags GetNpcFlags() const { return NPCFlags(GetUInt32Value(UNIT_NPC_FLAGS)); }
bool HasNpcFlag(NPCFlags flags) const { return HasFlag(UNIT_NPC_FLAGS, flags) != 0; }
@@ -2044,6 +2047,8 @@ protected:
void _UpdateAutoRepeatSpell();
bool CanSparringWith(Unit const* attacker) const; ///@brief: Check if unit is eligible for sparring damages. Work only if attacker and victim are creatures.
bool IsAlwaysVisibleFor(WorldObject const* seer) const override;
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
+36
View File
@@ -2298,6 +2298,42 @@ void ObjectMgr::LoadCreatures()
LOG_INFO("server.loading", " ");
}
void ObjectMgr::LoadCreatureSparring()
{
uint32 oldMSTime = getMSTime();
QueryResult result = WorldDatabase.Query("SELECT GUID, SparringPCT FROM creature_sparring");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 sparring data. DB table `creature_sparring` is empty.");
LOG_INFO("server.loading", " ");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
ObjectGuid::LowType spawnId = fields[0].Get<uint32>();
float sparringHealthPct = fields[1].Get<float>();
if (!sObjectMgr->GetCreatureData(spawnId))
{
LOG_ERROR("sql.sql", "Entry {} has a record in `creature_sparring` but doesn't exist in `creatures` table");
continue;
}
_creatureSparringStore[spawnId].push_back(sparringHealthPct);
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} sparring data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const* data)
{
uint8 mask = data->spawnMask;
+8
View File
@@ -751,6 +751,8 @@ public:
typedef std::map<uint32, uint32> CharacterConversionMap;
typedef std::unordered_map<ObjectGuid::LowType, std::vector<float>> CreatureSparringContainer;
GameObjectTemplate const* GetGameObjectTemplate(uint32 entry);
bool IsGameObjectStaticTransport(uint32 entry);
[[nodiscard]] GameObjectTemplateContainer const* GetGameObjectTemplates() const { return &_gameObjectTemplateStore; }
@@ -1029,6 +1031,7 @@ public:
void LoadCreatureQuestItems();
void LoadTempSummons();
void LoadCreatures();
void LoadCreatureSparring();
void LoadLinkedRespawn();
bool SetCreatureLinkedRespawn(ObjectGuid::LowType guid, ObjectGuid::LowType linkedGuid);
void LoadCreatureAddons();
@@ -1202,6 +1205,9 @@ public:
if (itr == _creatureDataStore.end()) return nullptr;
return &itr->second;
}
[[nodiscard]] CreatureSparringContainer const& GetSparringData() const { return _creatureSparringStore; }
CreatureData& NewOrExistCreatureData(ObjectGuid::LowType spawnId) { return _creatureDataStore[spawnId]; }
void DeleteCreatureData(ObjectGuid::LowType spawnId);
[[nodiscard]] ObjectGuid GetLinkedRespawnGuid(ObjectGuid guid) const
@@ -1527,6 +1533,8 @@ private:
PageTextContainer _pageTextStore;
InstanceTemplateContainer _instanceTemplateStore;
CreatureSparringContainer _creatureSparringStore;
private:
void LoadScripts(ScriptsType type);
void LoadQuestRelationsHelper(QuestRelations& map, std::string const& table, bool starter, bool go);
@@ -749,6 +749,9 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData)
if (usable)
{
AuctionHouseUsablePlayerInfo usablePlayerInfo;
usablePlayerInfo.classMask = GetPlayer()->getClassMask();
usablePlayerInfo.raceMask = GetPlayer()->getRaceMask();
usablePlayerInfo.level = GetPlayer()->GetLevel();
SkillStatusMap const& skillMap = GetPlayer()->GetSkillStatusMap();
for (auto const& pair : skillMap)
+2 -1
View File
@@ -111,7 +111,8 @@ enum AcoreStrings
LANG_RBAC_PERM_REVOKED_NOT_IN_LIST = 79,
LANG_PVPSTATS = 80,
LANG_PVPSTATS_DISABLED = 81,
// Free 82 - 86
LANG_GENERIC_TWO_CURLIES_WITH_COLON = 82,
// Free 83 - 86
LANG_UNKNOWN_ERROR = 87,
LANG_2FA_COMMANDS_NOT_SETUP = 88,
+69 -87
View File
@@ -39,11 +39,6 @@ MotdMgr* MotdMgr::instance()
return &instance;
}
bool MotdMgr::IsValidLocale(std::string const& locale) {
// Use std::find to search for the locale in the array
return std::find(std::begin(localeNames), std::end(localeNames), locale) != std::end(localeNames);
}
void MotdMgr::SetMotd(std::string motd, LocaleConstant locale)
{
// scripts may change motd
@@ -53,31 +48,76 @@ void MotdMgr::SetMotd(std::string motd, LocaleConstant locale)
MotdPackets[locale] = CreateWorldPacket(motd);
}
void MotdMgr::CreateWorldPackages()
{
for (auto const& [locale, motd] : MotdMap)
// Store the constructed packet in MotdPackets with the locale as the key
MotdPackets[locale] = CreateWorldPacket(motd);
}
void MotdMgr::LoadMotd()
{
uint32 oldMSTime = getMSTime();
uint32 realmId = sConfigMgr->GetOption<int32>("RealmID", 0);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
// Load the main motd for the realm and assign it to enUS if available
std::string motd = LoadDefaultMotd(realmId);
if (result)
{
Field* fields = result->Fetch();
std::string motd = fields[0].Get<std::string>();
// Check if motd was loaded; if not, set default only for enUS
if (motd.empty())
SetDefaultMotd(); // Only sets enUS default if motd is empty
SetMotd(motd, LOCALE_enUS);
LoadMotdLocale();
}
else
MotdMap[DEFAULT_LOCALE] = motd; // Assign the loaded motd to enUS
{
LOG_INFO("server.loading", ">> Loaded 0 motd definitions. DB table `motd` is empty for this realm!");
LOG_INFO("server.loading", ">> Loaded 0 motd locale definitions. DB table `motd` needs an entry to be able to load DB table `motd_locale`!");
LOG_INFO("server.loading", " ");
}
// Load localized texts if available
LoadLocalizedMotds(realmId);
LOG_INFO("server.loading", ">> Loaded motd definitions in {} ms", GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
// Create all world packages after loading motd and localized texts
CreateWorldPackages();
void MotdMgr::LoadMotdLocale()
{
uint32 oldMSTime = getMSTime();
uint32 count = 0;
LOG_INFO("server.loading", "Loading Motd locale...");
uint32 realmId = sConfigMgr->GetOption<int32>("RealmID", 0);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD_LOCALE);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
{
do
{
Field* fields = result->Fetch();
// fields[0] is the locale string and fields[1] is the localized motd text
std::string locale = fields[0].Get<std::string>();
std::string localizedText = fields[1].Get<std::string>();
if (!IsLocaleValid(locale))
{
LOG_ERROR("server.loading", "DB table `motd_localized` has invalid locale ({}), skipped.", locale);
continue;
}
LocaleConstant localeId = GetLocaleByName(locale);
if (localeId == LOCALE_enUS)
continue;
SetMotd(localizedText, localeId);
++count;
} while (result->NextRow());
}
else
{
LOG_INFO("server.loading", ">> Loaded 0 motd locale definitions. DB table `motd_localized` is empty for this realm!");
LOG_INFO("server.loading", " ");
}
LOG_INFO("server.loading", ">> Loaded {} motd locale definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
}
char const* MotdMgr::GetMotd(LocaleConstant locale)
@@ -87,7 +127,7 @@ char const* MotdMgr::GetMotd(LocaleConstant locale)
if (it != MotdMap.end())
return it->second.c_str();
return MotdMap[DEFAULT_LOCALE].c_str(); // Fallback to enUS if locale is not found
return MotdMap[LOCALE_enUS].c_str(); // Fallback to enUS if locale is not found
}
WorldPacket const* MotdMgr::GetMotdPacket(LocaleConstant locale)
@@ -97,79 +137,21 @@ WorldPacket const* MotdMgr::GetMotdPacket(LocaleConstant locale)
if (it != MotdPackets.end())
return &it->second;
return &MotdPackets[DEFAULT_LOCALE]; // Fallback to enUS if locale is not found
return &MotdPackets[LOCALE_enUS]; // Fallback to enUS if locale is not found
}
std::string MotdMgr::LoadDefaultMotd(uint32 realmId)
WorldPacket MotdMgr::CreateWorldPacket(std::string motd)
{
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
// Create a new WorldPacket for this locale
WorldPacket data(SMSG_MOTD); // new in 2.0.1
if (result)
{
Field* fields = result->Fetch();
return fields[0].Get<std::string>(); // Return the main motd if found
}
return ""; // Return empty string if no motd found
}
void MotdMgr::SetDefaultMotd()
{
std::string motd = /* fctlsup << //0x338// "63"+"cx""d2"+"1e""dd"+"cx""ds"+"ce""dd"+"ce""7D"+ << */
/*"d3"+"ce"*/ std::string("@|") + "cf" +/*"as"+"k4"*/"fF" + "F4" +/*"d5"+"f3"*/"A2" + "DT"/*"F4"+"Az"*/ + "hi" + "s "
motd = /* fctlsup << //0x338// "63"+"cx""d2"+"1e""dd"+"cx""ds"+"ce""dd"+"ce""7D"+ << */ motd
/*"d3"+"ce"*/ + "@|" + "cf" +/*"as"+"k4"*/"fF" + "F4" +/*"d5"+"f3"*/"A2" + "DT"/*"F4"+"Az"*/ + "hi" + "s "
/*"fd"+"hy"*/ + "se" + "rv" +/*"nh"+"k3"*/"er" + " r" +/*"x1"+"A2"*/"un" + "s "/*"F2"+"Ay"*/ + "on" + " Az"
/*"xs"+"5n"*/ + "er" + "ot" +/*"xs"+"A2"*/"hC" + "or" +/*"a4"+"f3"*/"e|" + "r "/*"f2"+"A2"*/ + "|c" + "ff"
/*"5g"+"A2"*/ + "3C" + "E7" +/*"k5"+"AX"*/"FF" + "ww" +/*"sx"+"Gj"*/"w." + "az"/*"a1"+"vf"*/ + "er" + "ot"
/*"ds"+"sx"*/ + "hc" + "or" +/*"F4"+"k5"*/"e." + "or" +/*"po"+"xs"*/"g|r"/*"F4"+"p2"+"o4"+"A2"+"i2"*/;
MotdMap[DEFAULT_LOCALE] = motd;
// Log that no motd was found and a default is being used for enUS
LOG_WARN("server.loading", ">> Loaded 0 motd definitions. DB table `motd` is empty for this realm!");
LOG_INFO("server.loading", " ");
}
void MotdMgr::LoadLocalizedMotds(uint32 realmId) {
// First, check if base MOTD exists
LoginDatabasePreparedStatement* baseStmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD);
baseStmt->SetData(0, realmId);
PreparedQueryResult baseResult = LoginDatabase.Query(baseStmt);
if (!baseResult)
{
LOG_ERROR("server.loading", "No base MOTD found for realm {}. Localized MOTDs will not be loaded.", realmId);
return;
}
// Now load localized versions
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_MOTD_LOCALE);
stmt->SetData(0, realmId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
{
do {
Field* fields = result->Fetch();
// fields[0] is the locale string and fields[1] is the localized motd text
std::string localizedText = fields[1].Get<std::string>();
// Convert locale string to LocaleConstant
LocaleConstant localeId = GetLocaleByName(fields[0].Get<std::string>());
if (localeId == DEFAULT_LOCALE)
continue;
MotdMap[localeId] = localizedText;
} while (result->NextRow());
}
}
WorldPacket MotdMgr::CreateWorldPacket(std::string const& motd)
{
// Create a new WorldPacket for this locale
WorldPacket data(SMSG_MOTD); // new in 2.0.1
// Tokenize the motd string by '@'
std::vector<std::string_view> motdTokens = Acore::Tokenize(motd, '@', true);
data << uint32(motdTokens.size()); // line count
+3 -12
View File
@@ -29,9 +29,6 @@ class AC_GAME_API MotdMgr
public:
static MotdMgr* instance();
/// Converts the localized string to world packages
void CreateWorldPackages();
/// Set a new Message of the Day
void SetMotd(std::string motd, LocaleConstant locale);
@@ -44,18 +41,12 @@ public:
/// Returns the current motd packet for the given locale
WorldPacket const* GetMotdPacket(LocaleConstant locale);
// Checks if string is valid locale
bool IsValidLocale(std::string const& locale);
private:
// Loads the default motd from the motd table
std::string LoadDefaultMotd(uint32 realmId);
// Loads all available localized motd for the realm
void LoadLocalizedMotds(uint32 realmId);
// Sets the default mode if none is found in the database
void SetDefaultMotd();
void LoadMotdLocale();
// Create a worldpacket for a given motd localization
WorldPacket CreateWorldPacket(std::string const& motd);
WorldPacket CreateWorldPacket(std::string motd);
};
#define sMotdMgr MotdMgr::instance()
+4
View File
@@ -1761,6 +1761,9 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", "Loading Creature Data...");
sObjectMgr->LoadCreatures();
LOG_INFO("server.loading", "Loading Creature sparring...");
sObjectMgr->LoadCreatureSparring();
LOG_INFO("server.loading", "Loading Temporary Summon Data...");
sObjectMgr->LoadTempSummons(); // must be after LoadCreatureTemplates() and LoadGameObjectTemplates()
@@ -2029,6 +2032,7 @@ void World::SetInitialWorldSettings()
///- Load AutoBroadCast
LOG_INFO("server.loading", "Loading Autobroadcasts...");
sAutobroadcastMgr->LoadAutobroadcasts();
sAutobroadcastMgr->LoadAutobroadcastsLocalized();
///- Load Motd
LOG_INFO("server.loading", "Loading Motd...");