优化自定义前缀和后缀逻辑,之前会偶尔看不到自己或者别人的前缀后缀
This commit is contained in:
parent
78d665b15a
commit
960960ec52
@ -14,6 +14,54 @@
|
||||
#include "mod_CustomPlayerDataManager/CustomPlayerDataManager.h"
|
||||
#include <mod_CustomCharacterData.h>
|
||||
|
||||
// 预加载玩家前后缀
|
||||
void CustomNameCache::LoadAllCustomNames()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_cacheMutex);
|
||||
QueryResult result = CharacterDatabase.Query(
|
||||
"SELECT guid, namePrefix, nameSuffix FROM characters WHERE namePrefix != '' OR nameSuffix != ''"
|
||||
);
|
||||
|
||||
if (!result) return;
|
||||
|
||||
do {
|
||||
Field* fields = result->Fetch();
|
||||
uint64 guid = fields[0].Get<uint32>();
|
||||
std::string prefix = fields[1].Get<std::string>();
|
||||
std::string suffix = fields[2].Get<std::string>();
|
||||
|
||||
if (!prefix.empty() || !suffix.empty()) {
|
||||
_nameCache[guid] = CustomNameData(
|
||||
prefix.empty() ? "" : prefix + sSwitch->GetFlagByIndex(ST_SEP_PREFIX_SUFFIX, 1),
|
||||
suffix.empty() ? "" : sSwitch->GetFlagByIndex(ST_HOUZHUI_ID, 2) + suffix
|
||||
);
|
||||
}
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
CustomNameData* CustomNameCache::GetCustomNameData(uint64 guid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_cacheMutex);
|
||||
auto itr = _nameCache.find(guid);
|
||||
return (itr != _nameCache.end()) ? &itr->second : nullptr;
|
||||
|
||||
}
|
||||
|
||||
void CustomNameCache::UpdateCustomNameData(uint64 guid, const std::string& prefix, const std::string& suffix)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_cacheMutex);
|
||||
if (prefix.empty() && suffix.empty()) {
|
||||
_nameCache.erase(guid);
|
||||
}
|
||||
else {
|
||||
_nameCache[guid] = CustomNameData(
|
||||
prefix.empty() ? "" : prefix + sSwitch->GetFlagByIndex(ST_SEP_PREFIX_SUFFIX, 1),
|
||||
suffix.empty() ? "" : sSwitch->GetFlagByIndex(ST_HOUZHUI_ID, 2) + suffix
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新前缀
|
||||
void CharNameMod::UpdatePrefix(Player* player, const std::string& namePrefix)
|
||||
{
|
||||
uint64 playerGuid = player->GetGUID().GetCounter();
|
||||
@ -30,18 +78,14 @@ void CharNameMod::UpdatePrefix(Player* player, const std::string& namePrefix)
|
||||
else
|
||||
playerData->namePrefix = "";
|
||||
|
||||
// 构建完整显示名称时组合各部分
|
||||
std::string FFAPvP = (player-> GetUInt32Value(PLAYER_DUEL_TEAM) == player-> GetGUID().GetCounter()) ? sString-> GetText(STR_FFAPVP) : "";
|
||||
|
||||
std::string fullPrefix = FFAPvP + playerData->vipPrefix + playerData->namePrefix;
|
||||
|
||||
// 更新前缀客户端显示
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, fullPrefix, playerData->nameSuffix);
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, playerData->namePrefix, playerData->nameSuffix);
|
||||
|
||||
// 更新前缀到数据库
|
||||
sCustomCharacterDataConnection.UpdateNamePrefix(player->GetGUID(), namePrefix);
|
||||
}
|
||||
|
||||
// 更新后缀
|
||||
void CharNameMod::UpdateSuffix(Player* player, const std::string nameSuffix)
|
||||
{
|
||||
uint64 playerGuid = player->GetGUID().GetCounter();
|
||||
@ -54,14 +98,8 @@ void CharNameMod::UpdateSuffix(Player* player, const std::string nameSuffix)
|
||||
else
|
||||
playerData->nameSuffix = "";
|
||||
|
||||
// 重新组合完整名称
|
||||
std::string FFAPvP = (player->GetUInt32Value(PLAYER_DUEL_TEAM) == player->GetGUID().GetCounter())
|
||||
? sString->GetText(STR_FFAPVP) : "";
|
||||
|
||||
std::string fullPrefix = FFAPvP + playerData->vipPrefix + playerData->namePrefix;
|
||||
|
||||
// 更新后缀客户端显示
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, fullPrefix, playerData->nameSuffix);
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, playerData->namePrefix, playerData->nameSuffix);
|
||||
|
||||
// 更新后缀到数据库
|
||||
sCustomCharacterDataConnection.UpdateNameSuffix(player->GetGUID(), nameSuffix);
|
||||
@ -69,171 +107,240 @@ void CharNameMod::UpdateSuffix(Player* player, const std::string nameSuffix)
|
||||
|
||||
std::string CharNameMod::GetPureName(std::string name)
|
||||
{
|
||||
// 第一步:使用分隔符"·"进行第一次分割,移除前缀
|
||||
std::vector<std::string> vec = sCF->SplitStr(name, sSwitch->GetFlagByIndex(ST_SEP_PREFIX_SUFFIX, 1));
|
||||
// 输入: "好人·而亲爱的·杀人狂" 分割结果: vec = ["好人", "而亲爱的·杀人狂"]
|
||||
|
||||
// 第二步:检查分割结果,如果有多个部分说明存在前缀
|
||||
if (vec.size() > 1)
|
||||
name = vec[1];
|
||||
name = vec[1]; // 取第二部分,去掉前缀: "而亲爱的·杀人狂"
|
||||
else
|
||||
name = vec[0];
|
||||
name = vec[0]; // 如果没有前缀,保持原样
|
||||
|
||||
// 第三步:清空向量,准备第二次分割
|
||||
vec.clear();
|
||||
|
||||
// 第四步:使用分隔符"·"进行第二次分割,移除后缀
|
||||
vec = sCF->SplitStr(name, sSwitch->GetFlagByIndex(ST_SEP_PREFIX_SUFFIX, 2));
|
||||
|
||||
return vec[0];
|
||||
// 输入: "而亲爱的·杀人狂" 分割结果: vec = ["而亲爱的", "杀人狂"]
|
||||
// 第五步:返回第一部分,这就是纯净的玩家名
|
||||
return vec[0]; // 返回: "而亲爱的"
|
||||
}
|
||||
|
||||
//角色名称脚本
|
||||
class CharNameModPlayerScript : PlayerScript
|
||||
// CharNameMod.cpp - 核心实现
|
||||
class CharNameModPlayerScript : public PlayerScript
|
||||
{
|
||||
private:
|
||||
// 移除颜色代码的函数
|
||||
std::string RemoveColorCodes(const std::string& text)
|
||||
{
|
||||
std::string result = text;
|
||||
size_t pos = 0;
|
||||
|
||||
// 查找并移除 |cFFFFFFFF 格式的颜色开始标记
|
||||
while ((pos = result.find("|c", pos)) != std::string::npos)
|
||||
{
|
||||
// 颜色代码格式: |cAARRGGBB (10个字符)
|
||||
if (pos + 10 <= result.length())
|
||||
{
|
||||
result.erase(pos, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除所有 |r 颜色结束标记
|
||||
pos = 0;
|
||||
while ((pos = result.find("|r", pos)) != std::string::npos)
|
||||
{
|
||||
result.erase(pos, 2);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 检查字符串是否包含颜色代码
|
||||
bool HasColorCodes(const std::string& text)
|
||||
{
|
||||
return (text.find("|c") != std::string::npos || text.find("|r") != std::string::npos);
|
||||
}
|
||||
TaskScheduler _scheduler;
|
||||
|
||||
public:
|
||||
CharNameModPlayerScript() : PlayerScript("CharNameModPlayerScript") {}
|
||||
CharNameModPlayerScript() : PlayerScript("CharNameModPlayerScript") {}
|
||||
|
||||
void OnPlayerLogin(Player* player/*,bool*/) override
|
||||
{
|
||||
_ApplyCharName(player);
|
||||
}
|
||||
|
||||
void OnPlayerBeforeSendChatMessage(Player* player, uint32& type, uint32& lang, std::string& msg) override
|
||||
void OnPlayerFirstLogin(Player* player) override
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
// 只处理FFA PvP状态,因为VIP信息已经在其他地方处理了
|
||||
std::string FFAPvP = (player->GetUInt32Value(PLAYER_DUEL_TEAM) == player->GetGUID().GetCounter())
|
||||
? sString->GetText(STR_FFAPVP) : "";
|
||||
|
||||
if (!FFAPvP.empty())
|
||||
{
|
||||
// 清理颜色代码(如果需要)
|
||||
std::string cleanFFAPvP = HasColorCodes(FFAPvP) ? RemoveColorCodes(FFAPvP) : FFAPvP;
|
||||
msg = cleanFFAPvP + ": " + msg;
|
||||
}
|
||||
// 首次登录时预加载数据
|
||||
_ApplyCharNameFromCache(player);
|
||||
}
|
||||
|
||||
// // 添加聊天钩子来处理名称显示
|
||||
// void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg) override
|
||||
// {
|
||||
// // 在聊天消息中替换玩家名称,移除前缀后缀
|
||||
// _CleanChatMessage(player, msg);
|
||||
// }
|
||||
//
|
||||
// void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* receiver) override
|
||||
// {
|
||||
// _CleanChatMessage(player, msg);
|
||||
// }
|
||||
//
|
||||
// void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override
|
||||
// {
|
||||
// _CleanChatMessage(player, msg);
|
||||
// }
|
||||
//
|
||||
// void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override
|
||||
// {
|
||||
// _CleanChatMessage(player, msg);
|
||||
// }
|
||||
//
|
||||
// void OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Channel* channel) override
|
||||
// {
|
||||
// _CleanChatMessage(player, msg);
|
||||
// }
|
||||
//
|
||||
//private:
|
||||
// void _CleanChatMessage(Player* player, std::string& msg)
|
||||
// {
|
||||
// if (!player)
|
||||
// return;
|
||||
//
|
||||
// uint64 playerGuid = player->GetGUID().GetCounter();
|
||||
// auto playerData = g_CustomPlayerDataManager.GetOrCreatePlayerData(playerGuid);
|
||||
//
|
||||
// if (!playerData)
|
||||
// return;
|
||||
//
|
||||
// // 构建完整的显示名称(包含前缀后缀)
|
||||
// std::string FFAPvP = (player->GetUInt32Value(PLAYER_DUEL_TEAM) == player->GetGUID().GetCounter())
|
||||
// ? sString->GetText(STR_FFAPVP) : "";
|
||||
// std::string fullDisplayName = FFAPvP + playerData->namePrefix + player->GetName() + playerData->nameSuffix;
|
||||
//
|
||||
// // 直接替换显示名称为原始名称
|
||||
// size_t pos = 0;
|
||||
// while ((pos = msg.find(fullDisplayName, pos)) != std::string::npos)
|
||||
// {
|
||||
// msg.replace(pos, fullDisplayName.length(), player->GetName());
|
||||
// pos += player->GetName().length();
|
||||
// }
|
||||
// }
|
||||
void OnPlayerLogin(Player* player) override
|
||||
{
|
||||
// 立即应用缓存数据
|
||||
_ApplyCharNameFromCache(player);
|
||||
|
||||
void _ApplyCharName(Player* player)
|
||||
// 添加到地图缓存 - 新增优化
|
||||
sCustomNameCache->AddPlayerToMap(player->GetGUID().GetCounter(), player->GetMapId());
|
||||
|
||||
// 延迟500ms进行完整同步(保持你的工作设置)
|
||||
_scheduler.Schedule(500ms, [this, player](TaskContext /*context*/)
|
||||
{
|
||||
if (!player || !player->IsInWorld()) return;
|
||||
_ProcessCompleteNameSync(player);
|
||||
});
|
||||
}
|
||||
|
||||
// 登出时清理缓存
|
||||
void OnPlayerLogout(Player* player) override
|
||||
{
|
||||
sCustomNameCache->RemovePlayerFromMap(player->GetGUID().GetCounter(), player->GetMapId());
|
||||
}
|
||||
|
||||
// 区域切换时的名称同步
|
||||
void OnPlayerUpdateZone(Player* player, uint32 /*newZone*/, uint32 /*newArea*/) override
|
||||
{
|
||||
// 切换区域时更新地图缓存
|
||||
sCustomNameCache->RemovePlayerFromMap(player->GetGUID().GetCounter(), player->GetMapId());
|
||||
sCustomNameCache->AddPlayerToMap(player->GetGUID().GetCounter(), player->GetMapId());
|
||||
|
||||
// 延迟同步附近玩家名称
|
||||
_scheduler.Schedule(200ms, [this, player](TaskContext /*context*/)
|
||||
{
|
||||
if (!player || !player->IsInWorld()) return;
|
||||
_ProcessCompleteNameSync(player);
|
||||
});
|
||||
}
|
||||
|
||||
void OnPlayerUpdate(Player* player, uint32 p_time) override
|
||||
{
|
||||
_scheduler.Update(p_time);
|
||||
}
|
||||
|
||||
private:
|
||||
void _ApplyCharNameFromCache(Player* player)
|
||||
{
|
||||
uint64 playerGuid = player->GetGUID().GetCounter();
|
||||
auto playerData = g_CustomPlayerDataManager.GetOrCreatePlayerData(playerGuid);
|
||||
|
||||
std::string namePrefix = "";
|
||||
std::string nameSuffix = "";
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT namePrefix,nameSuffix FROM characters WHERE guid = '{}'", player->GetGUID().GetCounter());
|
||||
|
||||
if (result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
namePrefix = fields[0].Get<std::string>();
|
||||
nameSuffix = fields[1].Get<std::string>();
|
||||
// 验证数据完整性
|
||||
if (!playerData) {
|
||||
// 延迟重试,而不是直接失败
|
||||
_scheduler.Schedule(100ms, [this, player](TaskContext /*context*/) {
|
||||
if (player && player->IsInWorld()) {
|
||||
_ApplyCharNameFromCache(player);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!namePrefix.empty()) //增加 前缀前面显示VIP名称 因为名称长度有限制 注释掉前缀
|
||||
playerData->namePrefix = /*sVIP->GetVIPName(player->vipLevel).c_str() + */namePrefix + sSwitch->GetFlagByIndex(ST_SEP_PREFIX_SUFFIX, 1);
|
||||
if (CustomNameData* nameData = sCustomNameCache->GetCustomNameData(playerGuid)) {
|
||||
playerData->namePrefix = nameData->namePrefix + sSwitch->GetParam(ST_SEP_PREFIX_SUFFIX);
|
||||
playerData->nameSuffix = sSwitch->GetParam(ST_SEP_PREFIX_SUFFIX) + nameData->nameSuffix;
|
||||
}
|
||||
else {
|
||||
playerData->namePrefix = "";
|
||||
playerData->nameSuffix = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (!nameSuffix.empty())
|
||||
playerData->nameSuffix = sSwitch->GetFlagByIndex(ST_HOUZHUI_ID, 2) + nameSuffix;//改后缀ID
|
||||
void _ProcessCompleteNameSync(Player* player)
|
||||
{
|
||||
auto playerData = g_CustomPlayerDataManager.GetOrCreatePlayerData(player->GetGUID().GetCounter());
|
||||
if (!playerData) return;
|
||||
|
||||
if (!namePrefix.empty() || !nameSuffix.empty())
|
||||
{
|
||||
//sCustomWorldData->UpdateNamePrefixSuffix(player, playerData->namePrefix, playerData->nameSuffix);
|
||||
sCharNameMod->UpdatePrefix(player, namePrefix);
|
||||
sCharNameMod->UpdateSuffix( player, nameSuffix);
|
||||
// 1. 为玩家自己发送名字更新
|
||||
if (!playerData->namePrefix.empty() || !playerData->nameSuffix.empty()) {
|
||||
_SendNameUpdateToPlayer(player, player);
|
||||
}
|
||||
|
||||
sGS->UpdateGS(player);
|
||||
// 2. 优化:只处理同地图的玩家
|
||||
uint32 currentMapId = player->GetMapId();
|
||||
std::vector<uint64> mapPlayers = sCustomNameCache->GetPlayersInMap(currentMapId);
|
||||
|
||||
// 如果地图缓存为空,回退到原来的全服方式
|
||||
if (mapPlayers.empty()) {
|
||||
HashMapHolder<Player>::MapType const& players = ObjectAccessor::GetPlayers();
|
||||
for (auto const& pair : players) {
|
||||
if (Player* onlinePlayer = pair.second) {
|
||||
if (onlinePlayer != player && onlinePlayer->IsInWorld()) {
|
||||
auto onlineData = g_CustomPlayerDataManager.GetOrCreatePlayerData(onlinePlayer->GetGUID().GetCounter());
|
||||
if (onlineData && (!onlineData->namePrefix.empty() || !onlineData->nameSuffix.empty())) {
|
||||
_SendNameUpdateToPlayer(player, onlinePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
// 向已在线玩家发送新登录玩家的名字
|
||||
if (onlinePlayer != player && (!playerData->namePrefix.empty() || !playerData->nameSuffix.empty())) {
|
||||
_SendNameUpdateToPlayer(onlinePlayer, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 使用地图缓存优化
|
||||
for (uint64 guid : mapPlayers) {
|
||||
if (Player* onlinePlayer = ObjectAccessor::FindConnectedPlayer(ObjectGuid::Create<HighGuid::Player>(guid))) {
|
||||
if (onlinePlayer != player && onlinePlayer->IsInWorld()) {
|
||||
auto onlineData = g_CustomPlayerDataManager.GetOrCreatePlayerData(guid);
|
||||
if (onlineData && (!onlineData->namePrefix.empty() || !onlineData->nameSuffix.empty())) {
|
||||
_SendNameUpdateToPlayer(player, onlinePlayer);
|
||||
}
|
||||
|
||||
// 向已在线玩家发送新登录玩家的名字
|
||||
if (!playerData->namePrefix.empty() || !playerData->nameSuffix.empty()) {
|
||||
_SendNameUpdateToPlayer(onlinePlayer, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _SendNameUpdateToPlayer(Player* receiver, Player* targetPlayer)
|
||||
{
|
||||
auto targetData = g_CustomPlayerDataManager.GetOrCreatePlayerData(targetPlayer->GetGUID().GetCounter());
|
||||
if (!targetData) return;
|
||||
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 10));
|
||||
data.appendPackGUID(targetPlayer->GetGUID().GetCounter());
|
||||
data << uint8(0);
|
||||
data << targetData->namePrefix + targetPlayer->GetName() + targetData->nameSuffix;
|
||||
data << uint8(0);
|
||||
data << uint8(targetPlayer->getRace());
|
||||
data << uint8(targetPlayer->getGender());
|
||||
data << uint8(targetPlayer->getClass());
|
||||
data << uint8(0);
|
||||
|
||||
receiver->GetSession()->SendPacket(&data);
|
||||
sGCAddon->SendPacketTo(receiver, "GC_S_NAME_UPDATE", " ");
|
||||
}
|
||||
};
|
||||
|
||||
std::string CustomNameManager::GetDisplayName(Player* player)
|
||||
{
|
||||
uint64 playerGuid = player->GetGUID().GetCounter();
|
||||
auto playerData = g_CustomPlayerDataManager.GetOrCreatePlayerData(playerGuid);
|
||||
if (!playerData)
|
||||
return player->GetName();
|
||||
return playerData->namePrefix + player->GetName() + playerData->nameSuffix;
|
||||
}
|
||||
|
||||
void CustomNameManager::UpdateNameForAllClients(Player* player)
|
||||
{
|
||||
|
||||
std::string displayName = GetDisplayName(player);
|
||||
// 分离前缀和后缀
|
||||
std::string prefix = displayName.substr(0, displayName.find(player->GetName()));
|
||||
std::string suffix = displayName.substr(displayName.find(player->GetName()) + player->GetName().length());
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, prefix, suffix);
|
||||
|
||||
}
|
||||
|
||||
// 更新玩家的前后缀,并通知所有在线玩家
|
||||
void CustomWorldData::UpdateNamePrefixSuffix(Player* player, const std::string prefix, const std::string suffix)
|
||||
{
|
||||
ObjectGuid playerGuid = player->GetGUID();
|
||||
CharacterCacheEntryMap::iterator itr = _globalPlayerDataStore.find(playerGuid.GetCounter());
|
||||
if (itr == _globalPlayerDataStore.end())
|
||||
return;
|
||||
|
||||
itr->second.prefix = prefix;
|
||||
itr->second.suffix = suffix;
|
||||
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 10));
|
||||
data.appendPackGUID(player->GetGUID().GetCounter());
|
||||
data << uint8(0);
|
||||
data << prefix + itr->second.Name + suffix;
|
||||
data << uint8(0);
|
||||
data << uint8(itr->second.Race);
|
||||
data << uint8(itr->second.Sex);
|
||||
data << uint8(itr->second.Class);
|
||||
data << uint8(0);
|
||||
|
||||
HashMapHolder<Player>::MapType const& players = ObjectAccessor::GetPlayers();
|
||||
for (auto const& pair : players)
|
||||
{
|
||||
if (Player* receiver = pair.second)
|
||||
{
|
||||
if (receiver->GetSession() && receiver->IsInWorld())
|
||||
{
|
||||
receiver->GetSession()->SendPacket(&data);
|
||||
sGCAddon->SendPacketTo(receiver, "GC_S_NAME_UPDATE", " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddSC_CharNameMod()
|
||||
{
|
||||
new CharNameModPlayerScript();
|
||||
|
||||
@ -1,16 +1,110 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
struct CustomNameData
|
||||
{
|
||||
std::string namePrefix;
|
||||
std::string nameSuffix;
|
||||
std::string vipPrefix;
|
||||
|
||||
CustomNameData() = default;
|
||||
CustomNameData(const std::string& prefix, const std::string& suffix, const std::string& vip = "")
|
||||
: namePrefix(prefix), nameSuffix(suffix), vipPrefix(vip) {
|
||||
}
|
||||
};
|
||||
|
||||
class CustomNameCache
|
||||
{
|
||||
private:
|
||||
std::unordered_map<uint64, CustomNameData> _nameCache;
|
||||
std::unordered_map<uint32, std::unordered_set<uint64>> _mapPlayerCache; // 按地图缓存玩家
|
||||
std::mutex _cacheMutex; // 线程安全
|
||||
|
||||
public:
|
||||
static CustomNameCache* instance()
|
||||
{
|
||||
static CustomNameCache instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void LoadAllCustomNames();
|
||||
|
||||
CustomNameData* GetCustomNameData(uint64 guid);
|
||||
|
||||
void UpdateCustomNameData(uint64 guid, const std::string& prefix, const std::string& suffix);
|
||||
|
||||
// 新增:地图玩家缓存管理
|
||||
void AddPlayerToMap(uint64 playerGuid, uint32 mapId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_cacheMutex);
|
||||
_mapPlayerCache[mapId].insert(playerGuid);
|
||||
}
|
||||
|
||||
void RemovePlayerFromMap(uint64 playerGuid, uint32 mapId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_cacheMutex);
|
||||
auto it = _mapPlayerCache.find(mapId);
|
||||
if (it != _mapPlayerCache.end())
|
||||
{
|
||||
it->second.erase(playerGuid);
|
||||
if (it->second.empty())
|
||||
_mapPlayerCache.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint64> GetPlayersInMap(uint32 mapId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_cacheMutex);
|
||||
auto it = _mapPlayerCache.find(mapId);
|
||||
if (it != _mapPlayerCache.end())
|
||||
{
|
||||
return std::vector<uint64>(it->second.begin(), it->second.end());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
#define sCustomNameCache CustomNameCache::instance()
|
||||
|
||||
|
||||
class CharNameMod
|
||||
{
|
||||
public:
|
||||
static CharNameMod* instance()
|
||||
{
|
||||
static CharNameMod instance;
|
||||
return &instance;
|
||||
}
|
||||
void UpdatePrefix(Player* player, const std::string& namePrefix);
|
||||
void UpdateSuffix(Player* player, const std::string nameSuffix);
|
||||
std::string GetPureName(std::string name);
|
||||
static CharNameMod* instance()
|
||||
{
|
||||
static CharNameMod instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
// 预加载玩家前后缀
|
||||
void LoadAllCustomNames();
|
||||
|
||||
void UpdatePrefix(Player* player, const std::string& namePrefix);
|
||||
void UpdateSuffix(Player* player, const std::string nameSuffix);
|
||||
std::string GetPureName(std::string name);
|
||||
private:
|
||||
|
||||
};
|
||||
#define sCharNameMod CharNameMod::instance()
|
||||
|
||||
|
||||
class CustomNameManager
|
||||
{
|
||||
public:
|
||||
static CustomNameManager* instance()
|
||||
{
|
||||
static CustomNameManager instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
std::string GetDisplayName(Player* player); // 获取显示名字
|
||||
void UpdateNameForAllClients(Player* player); // 更新所有客户端的名字显示
|
||||
std::string GetPureName(const std::string& displayName) // 从显示名字提取原始名字
|
||||
{
|
||||
return sCharNameMod->GetPureName(displayName);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define sCustomNameManager CustomNameManager::instance()
|
||||
|
||||
@ -1434,7 +1434,8 @@ public:
|
||||
else
|
||||
namePrefix = "";
|
||||
|
||||
sCharNameMod->UpdatePrefix(target, namePrefix);
|
||||
//sCustomNameManager->UpdateNameForAllClients(target);
|
||||
sCharNameMod->UpdatePrefix(target, namePrefix);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << sCF->GetNameLink(target) << "获得[姓名前缀]" << namePrefix;
|
||||
|
||||
@ -100,79 +100,7 @@ void CustomWorldData::UpdateAllTopPlayerData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 更新玩家名称的前缀和后缀,并广播给所有在线玩家
|
||||
*
|
||||
* 该函数用于动态修改玩家的显示名称,在前端显示时添加自定义前缀和后缀。
|
||||
* 通过以下流程实现:
|
||||
* 1. 更新内存缓存中的前缀后缀数据
|
||||
* 2. 构建名称更新协议包
|
||||
* 3. 向所有在线玩家广播更新
|
||||
*
|
||||
* @param player 需要修改名称的玩家对象指针
|
||||
* @param prefix 要添加的前缀(如 "[VIP]")
|
||||
* @param suffix 要添加的后缀(如 "勇士")
|
||||
*/
|
||||
void CustomWorldData::UpdateNamePrefixSuffix(Player* player, const std::string prefix, const std::string suffix)
|
||||
{
|
||||
// 获取玩家的全局唯一标识符
|
||||
ObjectGuid playerGuid = player->GetGUID();
|
||||
|
||||
// 在全局玩家数据存储中查找该玩家的缓存条目
|
||||
CharacterCacheEntryMap::iterator itr = _globalPlayerDataStore.find(playerGuid.GetCounter());
|
||||
|
||||
if (itr == _globalPlayerDataStore.end())
|
||||
return;
|
||||
|
||||
itr->second.prefix = prefix;
|
||||
itr->second.suffix = suffix;
|
||||
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 1 + 1 + 1 + 10));
|
||||
data.appendPackGUID(player->GetGUID().GetCounter());
|
||||
|
||||
data << uint8(0);
|
||||
data << prefix + itr->second.Name + suffix;
|
||||
data << uint8(0);
|
||||
data << uint8(itr->second.Race);
|
||||
data << uint8(itr->second.Sex);
|
||||
data << uint8(itr->second.Class);
|
||||
data << uint8(0);
|
||||
|
||||
// 使用GUID而不是原始指针,避免悬空指针问题
|
||||
ObjectGuid targetPlayerGuid = playerGuid;
|
||||
uint32 targetAreaId = player->GetAreaId();
|
||||
|
||||
WorldSessionMgr::SessionMap const& sessionMap = sWorldSessionMgr->GetAllSessions();
|
||||
for (WorldSessionMgr::SessionMap::const_iterator sessionItr = sessionMap.begin(); sessionItr != sessionMap.end(); ++sessionItr)
|
||||
{
|
||||
if (Player* pl = sessionItr->second->GetPlayer())
|
||||
{
|
||||
ObjectGuid receiverGuid = pl->GetGUID();
|
||||
|
||||
std::thread([this, receiverGuid, data, targetPlayerGuid, targetAreaId]()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
// 重新获取玩家对象,确保安全性
|
||||
Player* receiver = ObjectAccessor::FindPlayer(receiverGuid);
|
||||
Player* targetPlayer = ObjectAccessor::FindPlayer(targetPlayerGuid);
|
||||
|
||||
if (!receiver || !receiver->GetSession() || !receiver->IsInWorld())
|
||||
return;
|
||||
|
||||
if (!targetPlayer || !targetPlayer->IsInWorld())
|
||||
return;
|
||||
|
||||
// 只向同区域玩家发送名称更新
|
||||
if (receiver->GetAreaId() == targetAreaId)
|
||||
{
|
||||
receiver->GetSession()->SendPacket(&data);
|
||||
sGCAddon->SendPacketTo(receiver, "GC_S_NAME_UPDATE", " ");
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
//guid 账户ID 名称 性别 种族 职业 等级 邮件数量 工会ID 天下第一名称
|
||||
void CustomWorldData::AddGlobalPlayerData(uint32 guid, uint32 accountId, std::string const& name, uint8 Sex, uint8 race, uint8 playerClass, uint8 level, uint8 mailCount, uint32 guildId, std::string const& topname)
|
||||
{
|
||||
|
||||
@ -89,6 +89,7 @@
|
||||
#include <MirrorClone.h>
|
||||
#include <Mythic_Script.h>
|
||||
#include <HardcoreMode.h>
|
||||
#include <CharNameMod.h>
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
@ -181,6 +182,7 @@ void DataLoader::Load()
|
||||
|
||||
void DataLoader::LoadAll()
|
||||
{
|
||||
sCustomNameCache->LoadAllCustomNames(); // 自定义名称
|
||||
//sSpellMod->Load(); // _技能
|
||||
sSpellMgr->LoadSpellInfoCorrections(); // 加载官方核心数据 [修正法术属性]
|
||||
sRandomEnchant->Load(); // _物品_附魔提取与覆盖
|
||||
|
||||
@ -192,8 +192,8 @@ void PvP::Update(Player* player, uint32 zone, uint32 area)
|
||||
if (PvPVec[i].zone == zone && PvPVec[i].area == 0 || PvPVec[i].zone == zone && PvPVec[i].area == area)
|
||||
{
|
||||
// 构建完整前缀:FFA PvP + VIP + 区域前缀 + 玩家前缀
|
||||
std::string fullPrefix = FFAPvP + vipPrefix + PvPVec[i].prefix+ sSwitch->GetParam(ST_SEP_PREFIX_SUFFIX) + playerData->namePrefix;
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, fullPrefix, playerData->nameSuffix);
|
||||
// std::string fullPrefix = FFAPvP + vipPrefix + PvPVec[i].prefix+ sSwitch->GetParam(ST_SEP_PREFIX_SUFFIX) + playerData->namePrefix;
|
||||
// sCustomWorldData->UpdateNamePrefixSuffix(player, fullPrefix, playerData->nameSuffix);
|
||||
|
||||
if (!PvPVec[i].notice.empty())
|
||||
ChatHandler(player->GetSession()).PSendSysMessage(PvPVec[i].notice.c_str());
|
||||
@ -221,8 +221,8 @@ void PvP::Update(Player* player, uint32 zone, uint32 area)
|
||||
if (!exsit)
|
||||
{
|
||||
// 构建完整前缀:FFA PvP + VIP + 玩家前缀
|
||||
std::string fullPrefix = FFAPvP + vipPrefix + playerData->namePrefix;
|
||||
sCustomWorldData->UpdateNamePrefixSuffix(player, fullPrefix, playerData->nameSuffix);
|
||||
// std::string fullPrefix = FFAPvP + vipPrefix + playerData->namePrefix;
|
||||
// sCustomWorldData->UpdateNamePrefixSuffix(player, fullPrefix, playerData->nameSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -247,8 +247,8 @@ void Rank::Update(Player* player, uint32 value/* = 0*/, bool updateDB/* = false*
|
||||
playerData->rankValue = playerData->rankValue - playerData->maxRankValue;
|
||||
playerData->maxRankValue = GetMeetValue(playerData->rankLevel);
|
||||
|
||||
//更新前缀
|
||||
sCharNameMod->UpdatePrefix(player, GetPrefix(playerData->rankLevel));
|
||||
//更新前缀
|
||||
sCustomNameManager->UpdateNameForAllClients(player);
|
||||
|
||||
if (playerData->rankValue > playerData->maxRankValue)
|
||||
Update(player, 0, updateDB);
|
||||
@ -519,7 +519,7 @@ public:
|
||||
playerData->maxRankValue = MAX_LEVEL_DISPLAY_VALUE;
|
||||
}
|
||||
|
||||
sCharNameMod->UpdatePrefix(player, sRank->GetPrefix(playerData->rankLevel));
|
||||
sCustomNameManager->UpdateNameForAllClients(player);
|
||||
|
||||
sGCAddon->SendCharData(player);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user