加载中...

「RO 笔记」npc_market_fromsql 警告修复


0x00 前言

在启动 rAthena 的时候,有时会出现类似的 npc_market_fromsql 警告 :

[警告]: npc_market_fromsql: Item Hunting_Arrow [1774] discounted buying price (5->3) is less than overcharged selling price (5->6) in table 'market'. Assigning to current sell value.
[警告]: npc_market_fromsql: Item Gold [969] discounted buying price (75000->56250) is less than overcharged selling price (75000->93000) in table 'market'. Assigning to current sell value.

在 rAthena 论坛也有人问类似的问题《[BUG] Failure to purchase some items》,但是没解决。

0x10 分析

其实这个警告是在提醒某些道具的 低价买进价格 比 高价卖出价格 还低。

rAthena 为避免玩家刷钱,在 src/npc.cpp 中有其实现代码:

if (list.value * 0.75 < id->value_sell * 1.24) { // Exploit possible: you can buy and sell back with profit
    ShowWarning("npc_market_fromsql: Item %s [%u] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) in table '%s'. Assigning to current sell value.\n",
        id->name.c_str(), list.nameid, list.value, (int)(list.value * 0.75), id->value_sell, (int)(id->value_sell * 1.24), market_table
    );
    list.value = id->value_sell;
}

从代码中可以看到与 market_table 有关,这个其实就是数据库的 market 表。

继续翻查写入 market_table 代码逻辑:

void npc_market_tosql(const char *exname, struct npc_item_list *list) {
    SqlStmt* stmt = SqlStmt_Malloc(mmysql_handle);
    if (SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `%s` (`name`,`nameid`,`price`,`amount`,`flag`) VALUES ('%s','%u','%d','%d','%" PRIu8 "')",
        market_table, exname, list->nameid, list->value, list->qty, list->flag) ||
        SQL_ERROR == SqlStmt_Execute(stmt))
        SqlStmt_ShowDebug(stmt);
    SqlStmt_Free(stmt);
}

可以发现当 NPC 脚本调用了 marketshop 函数时,就会把 NPC 脚本设定的道具价格缓存到数据库的 market 表。

script_commands.txt 得到 marketshop 函数的语法:

<map name>,<x>,<y>,<facing>%TAB%marketshop%TAB%<NPC Name>%TAB%<sprite id>,<itemid>:<price>:<stock>{,<itemid>:<price>:<stock>...}

marketshop 函数设定的售价 <price> 会缓存到 market 表的 price 字段。

而道具本身在 item_db_*.yml 有设置其 Buy 属性的买入价,出售价 Sell 属性一般无需指定,默认为 Buy/2

<price>Buy 的值满足以下公式时:

price * 0.75 < Buy/2 * 1.24 (低买 < 高卖)

就会触发文中开头的警告提示。

0x20 解决

正常情况下,其实只要针对警告的道具,提高 NPC 脚本中 marketshop 函数所设定的售价、或者干脆设置为 -1,就可以解决此问题。

当把 <price> 设为 -1 则,默认用 Buy/2 作为售价。

但是某些情况下,REPLACE INTO 没有成功替换缓存值,导致数据库的 market 表依然为错误的值,于是启动时还是会弹出警告。

正确的做法是:

  1. 修正 NPC 脚本的 marketshop 函数售价,确保其不满足 低买 < 高卖 公式
  2. 清空数据库的 market 的表缓存

即可解决此问题。


文章作者: EXP
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 EXP !
 本篇
「RO 笔记」npc_market_fromsql 警告修复 「RO 笔记」npc_market_fromsql 警告修复
npc_market_fromsql 警告源于 NPC 脚本设定的道具售价过低,可能导致玩家利用差价套利,本文分析了该警告的成因与解决方法。
2025-05-24
下一篇 
每日英语口语训练打卡 每日英语口语训练打卡
每日练习打卡记录,每次打卡需要完成三个训练:听力练习、语感练习、综合练习,每天累计练习 60min,直到能把中文思维转变为英文思维为止。
2025-04-16
  目录