游戏服务器中的全服邮件发送

游戏开发、运营过程中通常会有 “给全服所有玩家发送邮件” 的需求。

我个人的想法是,给每封全服邮件一个版本号,玩家上线时或定期向 “全服邮件中心” 查询更新的全服邮件。下面是 C++ 版本的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Global Mail Centra
using version_t = uint64;
using mail_id_t = uint64;

std::map<version_t, mail_id_t> _mails;

std::tuple<version_t, std::vector<mail_id_t>> fetchNewerMail(version_t currentVersion) {
auto newerVersion = currentVersion;
std::vector<mail_id_t> newerMails;
for (auto it = _mails.upper_bound(currentVersion); it != _mails.end(); ++it) {
newerVersion = it->first;
newerMails.push_back(it->second);
}
return std::make_tuple(newerVersion, newerMails);
}


// Global Mail Proxy in Player Module
version_t _currentVersion;

std::vector<mail_id_t> checkGlobalMails() {
version_t newerVersion;
std::vector<mail_id_t> newerMails;
std::tie(newerVersion, newerMails) = fetchNewerMails(_currentVersion);
if (newerVersion != _currentVersion) {
_currentVersion = newerVersion;
// update _currentVersion to backend data storage
}
return newerMails;
}

如果服务器框架有很好的 coroutine 支持,玩家模块可以用一个独立的 coroutine 不停的向 “全服邮件中心” 获取邮件更新;“全服邮件中心” 根据自身状态决定立即或延迟回复以恢复对方的执行流。例如,在 skynet 中,可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
function update_global_mails()
local currentVersion = get_current_version()
while true do
newerVersion, newerMails = skynet.call(".global_mail_centra", "lua", "fetchNewerMails", currentVersion)
if newerVersion != currentVersion then
// synchronized to player's mailbox (other module in same process), blocking call
currentVersion = newerVersion
// update currentVersion to backend data storage
end
end
end

skynet.fork(update_global_mails)

推荐阅读:skynet 中如何实现邮件达到通知服务