[硬核模式]优化:
1、player类BuildEnumData函数优化发送方案,不在需要在characters表中加入“硬核模式”字段,而是JOIN方式挂载到自定义表“角色硬核模式”的“角色编号”字段 2、设置死亡后记录详细日志信息 3、增加新的HardcoreStatus模式,辨别各种模式 0:从未选择过硬核模式 1:正在进行硬核模式 2:硬核模式中死亡 3:已完成硬核模式
This commit is contained in:
parent
22f07eab1d
commit
78d665b15a
@ -14,8 +14,8 @@ HardcoreDatabase* HardcoreDatabase::instance()
|
||||
|
||||
bool HardcoreDatabase::LoadHardcoreData(uint32 playerGuid, HardcoreData& data)
|
||||
{
|
||||
std::string query = Acore::StringFormat("SELECT 角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号,奖励已领取 FROM 角色硬核模式 WHERE 角色编号 = {}", playerGuid);
|
||||
|
||||
std::string query = Acore::StringFormat("SELECT 角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 状态信息, 击杀者编号,是否已领取奖励 FROM 角色硬核模式 WHERE 角色编号 = {}", playerGuid);
|
||||
|
||||
QueryResult result = CharacterDatabase.Query(query);
|
||||
|
||||
if (!result)
|
||||
@ -30,7 +30,7 @@ bool HardcoreDatabase::LoadHardcoreData(uint32 playerGuid, HardcoreData& data)
|
||||
data.finalLevel = fields[5].Get<uint8>();
|
||||
data.deathCause = fields[6].Get<std::string>();
|
||||
data.killerGuid = fields[7].Get<uint32>();
|
||||
data.rewardReceived = fields[8].Get<bool>(); // 奖励领取状态
|
||||
data.rewardReceived = fields[8].Get<bool>(); // 加载奖励领取状态
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -40,8 +40,7 @@ void HardcoreDatabase::SaveHardcoreData(const HardcoreData& data)
|
||||
std::string escapedCause = data.deathCause;
|
||||
CharacterDatabase.EscapeString(escapedCause);
|
||||
|
||||
std::string query = Acore::StringFormat(
|
||||
"REPLACE INTO 角色硬核模式 (角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 死亡原因, 击杀者编号) VALUES ({}, {}, {}, {}, {}, {}, '{}', {})",
|
||||
std::string query = Acore::StringFormat("REPLACE INTO 角色硬核模式 (角色编号, 状态, 难度类型编号, 启用时间, 死亡时间, 最终等级, 状态信息, 击杀者编号,是否已领取奖励) VALUES ({}, {}, {}, {}, {}, {}, '{}', {}, {})",
|
||||
data.guid,
|
||||
static_cast<uint8>(data.status),
|
||||
data.difficultyTypeId,
|
||||
@ -50,7 +49,7 @@ void HardcoreDatabase::SaveHardcoreData(const HardcoreData& data)
|
||||
data.finalLevel,
|
||||
escapedCause,
|
||||
data.killerGuid,
|
||||
data.rewardReceived ? 1 : 0 // 新增:保存奖励领取状态
|
||||
data.rewardReceived ? 1 : 0 // 保存奖励领取状态
|
||||
);
|
||||
|
||||
CharacterDatabase.Execute(query);
|
||||
|
||||
@ -6,12 +6,13 @@
|
||||
#include "Define.h"
|
||||
#include "QueryResult.h"
|
||||
|
||||
// 前向声明,避免循环包含
|
||||
// 前向声明,避免循环包含
|
||||
enum HardcoreStatus : uint8
|
||||
{
|
||||
HC_STATUS_NORMAL = 0, // 未启用硬核模式 - 玩家处于正常游戏模式
|
||||
HC_STATUS_HARDCORE= 1, // 已启用硬核模式 - 玩家处于硬核模式,死亡将是永久的
|
||||
HC_STATUS_DEAD = 2 // 硬核模式中已死亡 - 玩家在硬核模式中死亡,无法复活
|
||||
HC_STATUS_NORMAL = 0, // 从未选择过硬核模式
|
||||
HC_STATUS_HARDCORE = 1, // 正在进行硬核模式
|
||||
HC_STATUS_DEAD = 2, // 硬核模式中死亡
|
||||
HC_STATUS_COMPLETED = 3 // 已完成硬核模式
|
||||
};
|
||||
|
||||
struct HardcoreData
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -17,14 +17,14 @@ struct HardcoreModeType
|
||||
std::string subtitle; // 子标题
|
||||
std::string description; // 描述文本
|
||||
std::string backtexture; // 背景纹理
|
||||
std::string HardcoreLogo; // 难度标志图
|
||||
std::string RewBoxTexture; // 奖励宝箱纹理
|
||||
bool permanentDeath;
|
||||
float expModifier;
|
||||
uint32 groupRestrictions; // 组队限制
|
||||
bool questRestrictions;
|
||||
bool auctionRestrictions;
|
||||
uint32 RewID; // 奖励ID 关联【_模板_奖励】表
|
||||
std::string HardcoreLogo; // 难度标志图
|
||||
std::string RewBoxTexture; // 奖励宝箱纹理
|
||||
bool permanentDeath; // 永久死亡
|
||||
float expModifier; // 经验倍率
|
||||
uint32 groupRestrictions; // 组队限制
|
||||
bool questRestrictions; // 任务限制
|
||||
bool auctionRestrictions; // 拍卖行限制
|
||||
uint32 RewID; // 奖励ID 关联【_模板_奖励】表
|
||||
};
|
||||
|
||||
class HardcoreMode
|
||||
@ -32,15 +32,14 @@ class HardcoreMode
|
||||
public:
|
||||
static HardcoreMode* instance();
|
||||
|
||||
bool IsHardcorePlayer(Player* player);
|
||||
bool IsHardcorePlayer(Player* player);// 玩家是否开启了硬核模式
|
||||
HardcoreStatus GetHardcoreStatus(Player* player);
|
||||
HardcoreStatus GetHardcoreStatusByGuid(uint32 guid);
|
||||
void EnableHardcoreMode(Player* player, uint32 difficultyTypeId);
|
||||
void EnableHardcoreModeForOfflineCharacter(uint32 guid);
|
||||
void EnableHardcoreModeForOfflineCharacter(uint32 guid); // 命令启用硬核模式
|
||||
void DisableHardcoreModeForOfflineCharacter(uint32 guid);
|
||||
void SetPlayerDead(Player* player, const std::string& cause, Unit* killer = nullptr);
|
||||
bool HasPermanentDeath(Player* player); // 检查玩家的难度类型是否有永久死亡
|
||||
bool CanResurrect(Player* player);
|
||||
bool CanGroupWith(Player* player, Player* target);
|
||||
void LoadHardcoreData(Player* player);
|
||||
void SaveHardcoreData(const HardcoreData& data);
|
||||
void SetPlayerDifficultyType(Player* player, uint32 difficultyTypeId); // 当玩家选择特定难度时,需要将难度类型ID存储到玩家的硬核数据中
|
||||
@ -72,6 +71,7 @@ public:
|
||||
void GiveHardcoreReward(Player* player);
|
||||
bool HasReceivedHardcoreReward(Player* player);
|
||||
void MarkHardcoreRewardAsGiven(Player* player);
|
||||
void SetPlayerHardcoreCompleted(uint32 guid); // 完成状态设置
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32, HardcoreData> _hardcoreData;
|
||||
@ -86,56 +86,59 @@ private:
|
||||
class HardcorePlayerScript : public PlayerScript
|
||||
{
|
||||
public:
|
||||
HardcorePlayerScript() : PlayerScript("HardcorePlayerScript") { }
|
||||
HardcorePlayerScript() : PlayerScript("HardcorePlayerScript") {}
|
||||
|
||||
void OnPlayerFirstLogin(Player* player) override; // 当角色创建时调用
|
||||
void OnPlayerLogin(Player* player) override;
|
||||
void OnPlayerLogout(Player* player) override;
|
||||
bool OnPlayerCanResurrect(Player* player) override;
|
||||
void OnPlayerJustDied(Player* player) override;
|
||||
void OnPlayerPVPKill(Player* killer, Player* killed) override;
|
||||
void OnPlayerKilledByCreature(Creature* killer, Player* killed) override;
|
||||
void OnPlayerReleasedGhost(Player* player) override;
|
||||
void OnPlayerUpdate(Player* player, uint32 p_time) override;
|
||||
|
||||
bool OnPlayerCanGroupInvite(Player* player, std::string& membername) override; // 限制组队行为
|
||||
bool OnPlayerCanGroupAccept(Player* player, Group* group) override; // 限制接受组队行为
|
||||
bool OnPlayerCanPlaceAuctionBid(Player* /*player*/, AuctionEntry* /*auction*/)override; // 拍卖行交易
|
||||
bool OnPlayerCanGroupInvite(Player* player, std::string& membername) override; // 限制组队行为
|
||||
bool OnPlayerCanGroupAccept(Player* player, Group* group) override; // 限制接受组队行为
|
||||
bool OnPlayerCanPlaceAuctionBid(Player* /*player*/, AuctionEntry* /*auction*/)override; // 拍卖行交易
|
||||
bool OnPlayerBeforeQuestComplete(Player* player, uint32 quest_id) override;
|
||||
void OnPlayerGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/, uint8 /*xpSource*/) override; // 玩家获得经验时调用
|
||||
void OnPlayerLevelChanged(Player* /*player*/, uint8 /*oldlevel*/) override; // 玩家等级发生变化后调用
|
||||
|
||||
void CheckGroupLevelRestrictions(Player* player); // 检查组队限制
|
||||
void OnPlayerLevelChanged(Player* /*player*/, uint8 /*oldlevel*/) override; // 玩家等级发生变化后调用
|
||||
|
||||
|
||||
// 限制玩家状态
|
||||
void ApplyHardcoreRestrictions(Player* player);
|
||||
|
||||
|
||||
|
||||
// 启动5秒定时器
|
||||
void StartHardcoreReminder(Player* player);
|
||||
|
||||
void CheckGroupLevelRestrictions(Player* player); // 检查组队限制
|
||||
void ApplyHardcoreRestrictions(Player* player); // 限制玩家状态
|
||||
void StartHardcoreReminder(Player* player); // 启动5秒定时器
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
std::unordered_set<uint32> _reminderPlayers; // 需要提醒的玩家GUID
|
||||
std::unordered_set<uint32> _reminderPlayers; // 需要提醒的玩家GUID
|
||||
std::unordered_map<uint32, uint64> _reminderStartTime; // 记录每个玩家的提醒开始时间
|
||||
std::unordered_map<uint32, uint32> _reminderCount; // 玩家GUID -> 提醒计数
|
||||
std::unordered_set<uint32> _processedDeaths; // 记录已处理的死亡
|
||||
|
||||
std::string GetMapName(Player* player);
|
||||
std::string GetAreaName(Player* player);
|
||||
std::string GetCreatureRankName(uint32 rank);
|
||||
std::string FormatPosition(float x, float y, float z);
|
||||
std::string FormatPvPDeathMessage(Player* killer, Player* killed);
|
||||
std::string FormatCreatureDeathMessage(Creature* killer, Player* killed);
|
||||
std::string GetEnvironmentalDeathMessage(Player* player);
|
||||
void SendDeathMessage(Player* player, const std::string& message);
|
||||
};
|
||||
|
||||
class HardcoreWorldScript : public WorldScript
|
||||
{
|
||||
public:
|
||||
HardcoreWorldScript() : WorldScript("HardcoreWorldScript") { }
|
||||
HardcoreWorldScript() : WorldScript("HardcoreWorldScript") {}
|
||||
|
||||
void OnAfterConfigLoad(bool reload) override;
|
||||
void OnStartup() override;
|
||||
};
|
||||
|
||||
// 新增:ServerScript 用于包处理
|
||||
// 包处理
|
||||
class HardcoreServerScript : public ServerScript
|
||||
{
|
||||
public:
|
||||
HardcoreServerScript() : ServerScript("HardcoreServerScript") { }
|
||||
|
||||
HardcoreServerScript() : ServerScript("HardcoreServerScript") {}
|
||||
bool CanPacketReceive(WorldSession* session, WorldPacket& packet) override;
|
||||
};
|
||||
|
||||
@ -147,19 +150,13 @@ public:
|
||||
Acore::ChatCommands::ChatCommandTable GetCommands() const override;
|
||||
|
||||
private:
|
||||
static bool HandleHardcoreEnableCommand(ChatHandler* handler);
|
||||
static bool HandleHardcoreEnableCommand(ChatHandler* handler); // 启用硬核模式
|
||||
static bool HandleHardcoreStatusCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target);
|
||||
static bool HandleHardcoreDisableCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target);
|
||||
static bool HandleHardcoreReviveCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target);
|
||||
|
||||
// 新增:替代操作码的命令
|
||||
static bool HandleHardcoreToggleCommand(ChatHandler* handler, Optional<std::string> characterName);
|
||||
|
||||
// 移除硬核模式
|
||||
static bool HandleHardcoreDelCommand(ChatHandler* handler, Optional<std::string> characterName);
|
||||
|
||||
|
||||
static bool HandleHardcoreListCommand(ChatHandler* handler);
|
||||
static bool HandleHardcoreDisableCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target); // 移除自己的硬核模式
|
||||
static bool HandleHardcoreReviveCommand(ChatHandler* handler, Optional<Acore::ChatCommands::PlayerIdentifier> target); // 复活硬核模式玩家
|
||||
static bool HandleHardcoreToggleCommand(ChatHandler* handler, Optional<std::string> characterName); // 切换命令处理器
|
||||
static bool HandleHardcoreDelCommand(ChatHandler* handler, Optional<std::string> characterName); // 移除硬核模式
|
||||
static bool HandleHardcoreListCommand(ChatHandler* handler);// 查看硬核模式列表
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -40,15 +40,39 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_GUID_BY_NAME_FILTER, "SELECT guid, name FROM characters WHERE name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE guid = ? ORDER BY unbandate", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.guid = ? AND character_banned.guid = characters.guid", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, "
|
||||
"gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.extra_flags, c.硬核模式 "
|
||||
"FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
|
||||
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL ORDER BY COALESCE(c.order, c.guid)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, "
|
||||
"c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, "
|
||||
"cb.guid, c.extra_flags, c.硬核模式, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? "
|
||||
"LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
|
||||
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL ORDER BY COALESCE(c.order, c.guid)", CONNECTION_ASYNC);
|
||||
|
||||
// [自定义模组:硬核模式] 添加角色硬核模式表的 LEFT JOIN 以获取难度类型
|
||||
PrepareStatement(CHAR_SEL_ENUM,
|
||||
"SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, "
|
||||
"c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, "
|
||||
"gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, "
|
||||
"cb.guid, c.extra_flags, hc.难度类型编号 " // [自定义] 从外部表读取硬核难度类型
|
||||
"FROM characters AS c "
|
||||
"LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? "
|
||||
"LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
|
||||
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 "
|
||||
"LEFT JOIN 角色硬核模式 AS hc ON c.guid = hc.角色编号 " // [自定义模组:硬核模式] 外部表关联
|
||||
"WHERE c.account = ? AND c.deleteInfos_Name IS NULL "
|
||||
"ORDER BY COALESCE(c.order, c.guid)",
|
||||
CONNECTION_ASYNC);
|
||||
|
||||
// [自定义模组:硬核模式] 调整字段顺序,将 declined name 保持在索引 25
|
||||
PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME,
|
||||
"SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, "
|
||||
"c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, "
|
||||
"gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, "
|
||||
"cb.guid, c.extra_flags, cd.genitive, hc.难度类型编号 " // [自定义] 调整顺序:先 genitive 后硬核模式
|
||||
"FROM characters AS c "
|
||||
"LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? "
|
||||
"LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid "
|
||||
"LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
|
||||
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 "
|
||||
"LEFT JOIN 角色硬核模式 AS hc ON c.guid = hc.角色编号 " // [自定义模组:硬核模式] 外部表关联
|
||||
"WHERE c.account = ? AND c.deleteInfos_Name IS NULL "
|
||||
"ORDER BY COALESCE(c.order, c.guid)",
|
||||
CONNECTION_ASYNC);
|
||||
|
||||
|
||||
PrepareStatement(CHAR_SEL_FREE_NAME, "SELECT guid, name, at_login FROM characters WHERE guid = ? AND account = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_NAME_DATA, "SELECT race, class, gender, level FROM characters WHERE guid = ?", CONNECTION_SYNCH);
|
||||
|
||||
@ -1147,12 +1147,24 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
|
||||
*data << uint8(hairColor);
|
||||
*data << uint8(facialStyle);
|
||||
|
||||
// 获取硬核模式状态 - 使用硬核模式字段
|
||||
uint8 hardcoreModeId = fields[25].Get<uint8>();
|
||||
// [自定义模组:硬核模式] 根据查询类型读取硬核模式字段 - 开始
|
||||
uint32 hardcoreModeId = 0;
|
||||
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
|
||||
{
|
||||
// CHAR_SEL_ENUM_DECLINED_NAME: 硬核模式在索引 26
|
||||
hardcoreModeId = fields[26].IsNull() ? 0 : fields[26].Get<uint32>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// CHAR_SEL_ENUM: 硬核模式在索引 25
|
||||
hardcoreModeId = fields[25].IsNull() ? 0 : fields[25].Get<uint32>();
|
||||
}
|
||||
|
||||
uint8 actualLevel = fields[10].Get<uint8>();
|
||||
// 如果是硬核模式(ID > 0),使用最高位标记
|
||||
bool isHardcore = hardcoreModeId > 0;
|
||||
bool isHardcore = hardcoreModeId > 1; // 只有难度类型 > 1 才是硬核模式
|
||||
uint8 encodedLevel = actualLevel | (isHardcore ? 1 << 7 : 0);
|
||||
// [自定义模组:硬核模式] 根据查询类型读取硬核模式字段 - 结束
|
||||
|
||||
*data << uint8(encodedLevel); // level
|
||||
*data << uint32(zone); // zone
|
||||
*data << uint32(fields[12].Get<uint16>()); // map
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@ -35,6 +35,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "../../../../modules/mod_GhostScripts/src/mod_CharNameMod/CharNameMod.h"
|
||||
|
||||
class Aura;
|
||||
|
||||
@ -66,6 +67,16 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData)
|
||||
recvData >> membername;
|
||||
recvData.read_skip<uint32>();
|
||||
|
||||
// 自定义名字清理逻辑 - 让拥有自定义前缀后缀的玩家能够正常组队
|
||||
if (sCharNameMod)
|
||||
{
|
||||
std::string cleanName = sCharNameMod->GetPureName(membername);
|
||||
if (!cleanName.empty() && cleanName != membername)
|
||||
{
|
||||
membername = cleanName; // 用清理后的纯净名称替换原始输入
|
||||
}
|
||||
}
|
||||
|
||||
// attempt add selected player
|
||||
|
||||
// cheating
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user