7、交易与拍卖行校验:异常价格检测、刷钱行为识别、物品复制漏洞防范
交易系统和拍卖行,说白了就是游戏经济的「大动脉」。我见过太多项目,战斗系统做得再牛,经济一崩盘,玩家全跑了。今天咱们就聊聊怎么守住这条生命线。
7.1 异常价格检测:别让市场变成过山车
价格异常,是刷钱和转移资产的前兆。我习惯从三个维度来卡这个口子。
7.1.1 静态价格阈值
每个物品都有个「合理价格区间」。比如一把新手剑,系统定价100金币,那成交价就不能低于10金币,也不能高于1000金币。这个阈值怎么定?
- 基础价:策划填表时给的参考价
- 浮动范围:我一般设 ±80%,太宽了等于没设
- 特殊物品:绑定物品、任务物品,直接禁止交易
核心逻辑:任何交易价格超出 [basePrice * 0.2, basePrice * 5] 这个区间,直接拦截并报警。
7.1.2 动态价格基线
静态阈值太死板了。你想想看,一件极品装备,全服就一把,卖贵点很正常。这时候就需要动态基线。
我做过一个方案:
// 伪代码:动态价格基线计算
class PriceBaseline {
// 滑动窗口,取最近100笔成交记录
windowSize = 100;
// 计算中位数,排除极端值
getBaseline(itemId) {
prices = getRecentTrades(itemId, this.windowSize);
sorted = prices.sort();
// 去掉最高最低各10%
trimmed = sorted.slice(10, 90);
return median(trimmed);
}
// 当前价格偏离基线超过300%,直接拒绝
validate(price, itemId) {
baseline = this.getBaseline(itemId);
if (price > baseline * 4 || price < baseline * 0.25) {
return false; // 异常
}
return true;
}
}
嗯,这里要注意:新物品刚上线时,历史数据是空的。我建议先用策划填的参考价作为初始基线,等攒够50笔真实交易后再切换到动态模式。
7.1.3 频次与总量控制
价格正常,不代表交易正常。我曾经遇到过一个案例:一个玩家用1金币买了1000个稀有材料,每个材料市场价100金币。单看价格,1金币确实异常,但更诡异的是——这个卖家在10秒内上架了1000个材料。
所以,频次和总量必须一起查:
| 维度 | 阈值 | 说明 |
|---|---|---|
| 单角色日交易次数 | ≤ 200次 | 超过直接临时封禁 |
| 单角色日交易总额 | ≤ 等级 * 10000 | 等级越低,上限越低 |
| 同IP交易对 | ≤ 50次/天 | 防止小号刷钱 |
| 新角色交易限制 | 注册满7天 | 防脚本批量建号 |
7.2 刷钱行为识别:从源头掐断
刷钱,说白了就是「低买高卖」的极端版本。但外挂不会傻到直接刷金币,他们通常会走一套「洗钱流程」。
7.2.1 资金流向追踪
我建议给每个角色建一个「资金流向图」。不是实时全量,而是采样记录:
- 收入来源:打怪、任务、交易、拍卖行
- 支出去向:购买装备、学习技能、交易给他人
- 异常模式:收入全是交易所得,支出全是转给同一个号
个人经验:我见过最隐蔽的刷钱方式,是用两个号互相买卖垃圾材料,每次价格只偏离10%,但一天交易几千次。这种「温水煮青蛙」式的刷钱,单看价格完全正常,但资金流向图一画就露馅了——两个号之间形成了闭环。
7.2.2 行为特征分析
刷钱脚本和正常玩家,行为模式差别很大。我总结了几条:
- 操作间隔:脚本的操作间隔几乎恒定,比如每0.5秒点一次。正常玩家会有波动。
- 鼠标轨迹:脚本的鼠标移动是直线,玩家是曲线。这个在客户端可以采集。
- 在线时长:脚本可以24小时在线,玩家做不到。
- 多开检测:同IP下超过3个角色同时交易,基本就是工作室。
为什么会这样?因为写外挂的人,通常只关注「功能实现」,很少去模拟「人类行为」。你想想看,正常人谁会凌晨4点准时上线,用同样的速度操作2小时?
7.2.3 经济模型校验
从宏观层面,游戏经济有个「总产出 = 总消耗 + 总沉淀」的恒等式。如果某个服务器的金币总量突然暴涨,那一定有问题。
我习惯每天跑一次全服经济快照:
-- SQL示例:每日经济快照
INSERT INTO economy_snapshot (server_id, snapshot_date, total_gold, total_items, active_users)
SELECT
server_id,
CURDATE(),
SUM(gold),
COUNT(item_id),
COUNT(DISTINCT user_id)
FROM player_assets
WHERE last_login >= DATE_SUB(NOW(), INTERVAL 7 DAY);
如果某天金币总量环比增长超过20%,我会立刻拉出所有大额交易记录,逐条排查。
7.3 物品复制漏洞防范:最致命的漏洞
物品复制,是游戏界的「核武器」。一旦出现,经济体系直接崩溃。我经历过一次,那感觉……嗯,不想再经历第二次。
7.3.1 复制漏洞的常见成因
| 漏洞类型 | 典型场景 | 危害等级 |
|---|---|---|
| 网络延迟导致的双花 | 玩家在交易确认前断线,物品扣除了但没给对方 | 高 |
| 数据库事务未加锁 | 并发请求下,同一物品被多次取出 | 极高 |
| 拍卖行竞拍回滚 | 竞拍结束时,利用回滚机制同时拿到物品和金币 | 高 |
| 邮件系统漏洞 | 附件物品在领取时,服务器未做幂等校验 | 中 |
7.3.2 核心防御:事务与锁
所有涉及物品转移的操作,必须放在数据库事务里。我个人的铁律是:
-- 伪代码:安全的物品转移
BEGIN TRANSACTION;
-- 第一步:锁定双方行
SELECT * FROM player_items WHERE owner_id = ? FOR UPDATE;
SELECT * FROM player_items WHERE owner_id = ? FOR UPDATE;
-- 第二步:检查物品是否存在
IF (source_item.count < 1) THEN
ROLLBACK;
RETURN '物品不存在';
END IF;
-- 第三步:转移
UPDATE player_items SET count = count - 1 WHERE id = ?;
UPDATE player_items SET count = count + 1 WHERE id = ?;
-- 第四步:记录日志
INSERT INTO trade_log (from_id, to_id, item_id, time) VALUES (?, ?, ?, NOW());
COMMIT;
注意:千万不要用「先扣再还」的逻辑。比如玩家A给B物品,先扣A的,如果B的背包满了,再还给A。这个「还」的过程一旦出问题,物品就凭空消失了——或者更糟,被复制了。
7.3.3 幂等性与唯一ID
每个交易请求,必须携带一个全局唯一的请求ID。服务器收到请求后,先查这个ID是否处理过。如果处理过,直接返回上次的结果,不再执行。
我见过一个案例:玩家用脚本快速点击「领取邮件附件」,由于网络抖动,同一个请求被发送了两次。服务器第一次处理成功,第二次又处理了一次——结果玩家拿到了双倍物品。
解决方案很简单:
// 幂等校验
if (redis.exists(requestId)) {
return redis.get(requestId); // 返回上次结果
}
// 执行真正的业务逻辑
result = doTransfer();
// 缓存结果
redis.set(requestId, result, 3600);
return result;
7.3.4 物品唯一标识与追踪
对于高价值物品(比如极品装备、稀有材料),我建议使用「物品实例ID」。每个物品从产出到销毁,都有一个唯一的ID。这样,即使出现复制,也能通过ID追踪到所有副本。
举个例子:
- 物品A的实例ID是
item_123456 - 正常情况下,全服只能有一个
item_123456 - 如果数据库里出现了两个
item_123456,那一定是复制了
我习惯每天跑一次全服物品实例去重检查:
-- 检测重复实例
SELECT instance_id, COUNT(*) as cnt
FROM player_items
WHERE instance_id IS NOT NULL
GROUP BY instance_id
HAVING cnt > 1;
一旦发现重复,立刻冻结所有相关账号,人工介入处理。
7.4 架构层面的统一校验
说了这么多,其实核心就一句话:所有交易行为,必须经过统一的经济校验服务。不要在每个业务模块里各自写校验逻辑,那样容易漏,也容易不一致。
我画了一张图,展示校验流程:
你看,所有请求先进统一校验服务,然后并行跑三个模块。任何一个模块返回拒绝,整个交易就终止。这样设计的好处是:
- 扩展性强:以后加新的校验规则,加一个模块就行
- 性能可控:三个模块可以部署在不同的进程里,并行执行
- 日志完整:每个请求的校验结果都记录,方便事后追溯
避坑指南:我曾经把校验逻辑写在业务代码里,结果业务迭代时,产品经理说「这个功能先上线,校验后面再加」——然后就没有然后了。所以,校验服务一定要独立部署,独立迭代,不受业务排期影响。
好了,交易与拍卖行的校验,核心就是这些。记住:价格、行为、复制,三个维度缺一不可。别等到经济崩了才想起来补漏洞,那时候就晚了。
公众号:蓝海资料掘金营,微信deep3321