Merge branch 'master' into Playerbot
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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...");
|
||||
|
||||
Reference in New Issue
Block a user