Fix null character access in server bonus status query
This commit is contained in:
@@ -63,6 +63,12 @@ struct CHARACTER_MANAGER {
|
||||
std::map<DWORD,Character*> mobs;
|
||||
static CHARACTER_MANAGER& instance() { static CHARACTER_MANAGER value; return value; }
|
||||
Character* Find(DWORD vid) { return mobs[vid]; }
|
||||
int GetMobExpRate(LPCHARACTER) { return 200; }
|
||||
int GetMobGoldAmountRate(LPCHARACTER) { return 300; }
|
||||
int GetMobGoldDropRate(LPCHARACTER) { return 400; }
|
||||
int GetMobItemRate(LPCHARACTER ch) { assert(ch); return 999; } // locale rules require a real character
|
||||
int GetGlobalMobItemRate() { return 500; }
|
||||
|
||||
};
|
||||
using LPSECTREE=Sectree*;
|
||||
struct SectreeMap {
|
||||
@@ -90,6 +96,12 @@ int get_global_time() { return now; }
|
||||
#define ACMD(name) void name(LPCHARACTER ch,const char* argument)
|
||||
#define MT_AUTOHUNT_SERVER_TEST
|
||||
#include "../../tools/server/autohunt-pull/autohunt_pull.h"
|
||||
constexpr int PRIV_EXP_PCT=4, PRIV_ITEM_DROP=1, PRIV_GOLD_DROP=2, PRIV_GOLD10_DROP=3;
|
||||
struct CPrivManager {
|
||||
static CPrivManager& instance() { static CPrivManager pm; return pm; }
|
||||
int GetPriv(LPCHARACTER ch, int type) { assert(ch); return type*10; }
|
||||
};
|
||||
#include "../../tools/server/autohunt-pull-range/server_bonuses.h"
|
||||
|
||||
int main() {
|
||||
Sectree sec;
|
||||
@@ -160,5 +172,17 @@ int main() {
|
||||
for(auto vid:ten.mobs) assert(vid/10 < 10);
|
||||
auto sparse=mt_autohunt::SelectGroups({{1,1,100,true},{1,2,110,true},{2,3,50,true}},20);
|
||||
assert(sparse.groups==2 && sparse.mobs.size()==3 && sparse.mobs[0]==3);
|
||||
// The status command must use the global item rate, never the locale getter with NULL.
|
||||
Character bonusOwner; bonusOwner.pc=true;
|
||||
do_server_bonuses(&bonusOwner, "");
|
||||
assert(bonusOwner.replies.back()=="ServerBonuses 200 300 400 500 40 10 20 30");
|
||||
do_server_bonuses(&bonusOwner, "");
|
||||
assert(bonusOwner.replies.size()==1);
|
||||
now+=2;
|
||||
do_server_bonuses(&bonusOwner, "");
|
||||
assert(bonusOwner.replies.size()==2);
|
||||
Character notPlayer;
|
||||
do_server_bonuses(¬Player, "");
|
||||
assert(notPlayer.replies.empty());
|
||||
puts("autohunt_pull_test: PASS");
|
||||
}
|
||||
|
||||
@@ -29,3 +29,17 @@ Android 点击图标可看到提示,macOS 悬停显示;FPS 移到顶部中
|
||||
`port.login_flow` 覆盖真实 Python 配置和聊天封包链、石头优先与回退、加成图标新增/更新/移除;
|
||||
桌面及 `MT_TEST_MOBILE=1` 均通过。Mi 8 Lite 真机在模拟服务器场景显示图标和“服务器经验 200%”提示。
|
||||
macOS app 与 Android Release native/debug APK 已构建;APK 已安装到 63c36adb。
|
||||
|
||||
## 加成查询崩溃修正
|
||||
|
||||
首次部署后,真实角色执行 `server_bonuses` 导致地图进程 SIGSEGV:
|
||||
`GetMobItemRate(NULL)` 在当前地区规则中调用 `CHARACTER::IsOverTime` 并解引用空角色。
|
||||
最初的模拟服务器显示测试没有执行真实服务端的地区分支,因此未覆盖这一故障。
|
||||
|
||||
修正增加 `CHARACTER_MANAGER::GetGlobalMobItemRate()`,直接读取全局倍率;
|
||||
奖励结算使用的角色倍率接口及地区规则保持不变。其余三个倍率接口原本就支持空角色。
|
||||
`host.autohunt_pull` 现在直接执行实际的 `server_bonuses.h` 命令,模拟地区接口拒绝空角色,
|
||||
检查全局物品倍率、四项活动加成、非玩家过滤和查询冷却。
|
||||
|
||||
故障期间已回滚到 `/root/backup-bin/20261001-075226/` 恢复服务,崩溃栈和 core 保存在
|
||||
`/root/autohunt-range-20260930/`;修复构建目录为 `/root/rebuild/20261001-080615/`。
|
||||
|
||||
@@ -142,16 +142,18 @@
|
||||
+int AutoHuntPullLeash(LPCHARACTER mob, LPCHARACTER victim);
|
||||
--- /dev/null
|
||||
+++ b/server/game/src/server_bonuses.h
|
||||
@@ -0,0 +1,12 @@
|
||||
@@ -0,0 +1,14 @@
|
||||
+// PORT: report actual global rates and the character's effective event privileges.
|
||||
+#ifndef MT_AUTOHUNT_SERVER_TEST
|
||||
+#include "priv_manager.h"
|
||||
+#endif
|
||||
+ACMD(do_server_bonuses) {
|
||||
+ if (!ch->IsPC() || get_global_time() < ch->GetQuestFlag("server_bonuses.next_query")) return;
|
||||
+ ch->SetQuestFlag("server_bonuses.next_query", get_global_time() + 2);
|
||||
+ CHARACTER_MANAGER& cm = CHARACTER_MANAGER::instance();
|
||||
+ CPrivManager& pm = CPrivManager::instance();
|
||||
+ ch->ChatPacket(CHAT_TYPE_COMMAND, "ServerBonuses %d %d %d %d %d %d %d %d",
|
||||
+ cm.GetMobExpRate(NULL), cm.GetMobGoldAmountRate(NULL), cm.GetMobGoldDropRate(NULL), cm.GetMobItemRate(NULL),
|
||||
+ cm.GetMobExpRate(NULL), cm.GetMobGoldAmountRate(NULL), cm.GetMobGoldDropRate(NULL), cm.GetGlobalMobItemRate(),
|
||||
+ pm.GetPriv(ch, PRIV_EXP_PCT), pm.GetPriv(ch, PRIV_ITEM_DROP),
|
||||
+ pm.GetPriv(ch, PRIV_GOLD_DROP), pm.GetPriv(ch, PRIV_GOLD10_DROP));
|
||||
+}
|
||||
@@ -174,3 +176,14 @@
|
||||
if (Return())
|
||||
return true;
|
||||
}
|
||||
--- a/server/game/src/char_manager.h
|
||||
+++ b/server/game/src/char_manager.h
|
||||
@@ -92,6 +92,8 @@
|
||||
void SetUserDamageRatePremium(int value) { m_iUserDamageRatePremium = value; }
|
||||
void SetUserDamageRate(int value ) { m_iUserDamageRate = value; }
|
||||
int GetMobItemRate(LPCHARACTER ch);
|
||||
+ // PORT: query the global rate without dereferencing a character in locale-specific rules.
|
||||
+ int GetGlobalMobItemRate() const { return m_iMobItemRate; }
|
||||
int GetMobDamageRate(LPCHARACTER ch);
|
||||
int GetMobGoldAmountRate(LPCHARACTER ch);
|
||||
int GetMobGoldDropRate(LPCHARACTER ch);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// PORT: report actual global rates and the character's effective event privileges.
|
||||
#ifndef MT_AUTOHUNT_SERVER_TEST
|
||||
#include "priv_manager.h"
|
||||
#endif
|
||||
ACMD(do_server_bonuses) {
|
||||
if (!ch->IsPC() || get_global_time() < ch->GetQuestFlag("server_bonuses.next_query")) return;
|
||||
ch->SetQuestFlag("server_bonuses.next_query", get_global_time() + 2);
|
||||
CHARACTER_MANAGER& cm = CHARACTER_MANAGER::instance();
|
||||
CPrivManager& pm = CPrivManager::instance();
|
||||
ch->ChatPacket(CHAT_TYPE_COMMAND, "ServerBonuses %d %d %d %d %d %d %d %d",
|
||||
cm.GetMobExpRate(NULL), cm.GetMobGoldAmountRate(NULL), cm.GetMobGoldDropRate(NULL), cm.GetMobItemRate(NULL),
|
||||
cm.GetMobExpRate(NULL), cm.GetMobGoldAmountRate(NULL), cm.GetMobGoldDropRate(NULL), cm.GetGlobalMobItemRate(),
|
||||
pm.GetPriv(ch, PRIV_EXP_PCT), pm.GetPriv(ch, PRIV_ITEM_DROP),
|
||||
pm.GetPriv(ch, PRIV_GOLD_DROP), pm.GetPriv(ch, PRIV_GOLD10_DROP));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user