CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
后端接口

【后端接口】邮件系统:附件流转与离线投递

2026-09-21 18:14 作者:996 技术组 后端接口

实战应用:用在哪里

邮件是游戏的物流系统:补偿发放、行会周奖、玩家互寄的装备与元宝全走邮件,收件人下线也要把东西送到手。邮件的实现要点是附件的托管流转、离线的投递时序与过期退回的完整回路。

附件的托管

lua

---寄件:附件从寄件人背包转托管
function Mail.sendWithAtt(actor, toName, title, attIdx)
    local toId = Role.idOf(toName)
    if not toId then
        sendmsg(actor, 1, "收件人不存在")
        return false
    end
    -- 附件先从背包摘除进托管态
    local att = Mail.detach(actor, attIdx)
    DB.exec("INSERT INTO mails SET ?", {
        fromId = actor:GetUserId(), toId = toId,
        title = title, att = att, at = os.time(),
        expireAt = os.time() + 7 * 86400,
    })
    sendmsg(actor, 1, "邮件已寄出")
    if Online.isOnline(toId) then
        sendmsg(Role.actorOf(toId), 1, "收到新邮件:" .. title)
    end
    return true
end

寄件的第一步是把附件从背包摘除进托管态——裁决之杖寄出的瞬间就不再属于寄件人,两不占有的中间态杜绝复制漏洞。邮件行落库即完成投递的登记,在线的收件人即时收到提醒,离线的在下一次登录时拉取。附件的容量上限 5 格,超限的寄件被受理口拒绝。

收取与过期

lua

---收取:附件入包,邮件标记已领
function Mail.receive(actor, mailId)
    local m = Mail.load(mailId)
    if m.toId ~= actor:GetUserId() then
        return false
    end
    if m.claimed then
        sendmsg(actor, 1, "该邮件已领取")
        return false
    end
    if not giveitem(actor, m.attName, m.attCount) then
        sendmsg(actor, 1, "背包已满,请清理后领取")
        return false
    end
    Mail.markClaimed(mailId)
    return true
end

---过期退回:7 天未领取原路退回
setontimerex(81, 3600)
function Mail.expireScan()
    local rows = DB.query(
        "SELECT id, fromId, title FROM mails " ..
        "WHERE expire_at < ? AND claimed = 0", os.time())
    for _, r in ipairs(rows) do
        Mail.returnToSender(r.id, r.fromId, r.title)
    end
end

收取的校验链:归属校验防越权领件、背包满则不扣托管(附件原地保留),giveitem 成功才标记已领。过期的扫描每小时跑一轮:7 天未领的邮件连同附件原路退回寄件人,一件装备在两个邮箱之间的流转有始有终。系统邮件(补偿、周奖)的附件来自虚空不退回,个人邮件才走退回链路,两类邮件的标记区分开。

验证与监控

邮件表的堆积量监控,未领取的存量超过阈值即提醒玩家领取;退回链路的对账,退回后寄件人应收到托管附件。

踩坑记录

托管曾经与领取的标记非原子,收取一半的宕机让附件两空,事务包裹后杜绝。退回曾经不检查寄件人邮箱容量,来回退让的邮件死循环,退回件直接入托管不占格。背包满的领取曾经把附件扣了没给,giveitem 的失败分支回滚托管标记。

上线要点

附件的寄送费 1000 金币起按价值累进,倒金搬砖的成本抬升。系统邮件的模板集中管理,补偿的文案与金额由工单驱动生成。邮件的保留期分档:系统件 30 天、个人件 7 天,提示的倒计时在邮件列表常驻。

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

作者履历与出处

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

← 返回文章地图返回研学路径

最新技术文章 · 实战干货

LATEST ARTICLES

全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

玩法策划沙巴克税收

【玩法策划】沙城税务官:税收分配与廉政度的玩法设计

实战应用:用在哪里 沙巴克占领行会坐收税收却只进不出,非占领行会的玩家心里不平衡。税务官玩法把税收做成明账:占领行会对摆摊与…

2026-09-23 01:24 996 技术组
玩法策划比武社交

【玩法策划】比武招亲:比武切磋与社交绑定的玩法设计

实战应用:用在哪里 高端玩家婚姻系统只有仪式没有过程,社交绑定缺一个高光事件。比武招亲做成擂台玩法:擂主设擂摆彩头,攻擂者报…

2026-09-23 01:24 996 技术组
案例复盘限时礼包日期

【案例复盘】限时礼包少发一天的事故复盘

实战应用:用在哪里 开服七日限时礼包发到第六天断了粮,9 月 1 日当天领奖按钮灰的,投诉当天破千。事故根因是一条数字日期循…

2026-09-23 01:24 996 技术组
网络通信心跳假在线

【网络通信】心跳探测:半开连接的主动识别

实战应用:用在哪里 玩家拔线不退游戏,连接半开着,人不在指令也没有,在线数虚高,容量预案被假数据带着跑。心跳探测给每个在线玩…

2026-09-23 01:24 996 技术组
运维发布发布日历

【运维发布】发布日历:全月变更的集中排期

实战应用:用在哪里 周三发了合成系统补丁,周四又改强化概率,两条变更叠加后玩家分不清是哪个改出来的。发布日历把全月变更集中排…

2026-09-23 01:24 996 技术组
Lua实战滑动窗口计数

【Lua实战】时间窗口计数:滑动窗口的环形数组实现

实战应用:用在哪里 容量预案需要知道滚动一小时的副本进入峰值,而不是全天累计。滑动窗口用 60 个槽位每槽记一分钟的进入数,…

2026-09-23 01:24 996 技术组