综合实战:多人实时休闲游戏服务器(上)
概述
以多人实时休闲游戏(弹射对战/团队竞技)为例,实现实时对战服务器核心:同步方案选型(帧同步 vs 状态同步)、实时消息广播、房间内帧同步实现、AOI 视野管理。下篇补匹配池、分布式分片、弹性伸缩、反外挂与全链路监控。
一、同步方案选型
1.1 两种方案对比
帧同步(Lockstep):
服务器只转发客户端输入,各端本地计算
优点:流量小、服务器负载低
缺点:确定性要求高、作弊风险大(需服务端校验)
适合:格子类/计算量小的回合策略
状态同步(Authoritative):
服务器权威计算状态,广播增量
优点:安全(服务端权威)、易做回放
缺点:流量大、服务器负载高
适合:弹射/动作/需要防作弊的实时对战
选型决策:
弹射对战(物理+碰撞,防作弊)→ 状态同步
简化版策略对战(纯逻辑)→ 帧同步本项目选型(弹射对战):
核心:状态同步(服务端权威物理模拟)
输入:客户端发操作意图(角度/力度/技能)
输出:服务器算结果 → 增量广播(位置/血量)
兜底:快照同步(重连/校正用)1.2 双模式统一框架
抽象同步框架:
SyncMode { LOCKSTEP, STATE }
GameSync 接口:onInput / onTick / broadcastState
好处:
不同玩法可配不同模式
复用房间/连接/快照基础设施二、实时消息广播
2.1 广播通道
广播粒度:
房间广播:房间内所有玩家(对局状态)
队伍广播:同队成员(战术指令)
单播:单个玩家(个人提示)
场景广播:AOI 范围内玩家(见第三节)
实现:
房间 ChannelGroup(Netty ChannelGroup)
按玩家 Session 路由(在线表)
广播序列化一次,多连接复用(性能,见协议优化)// ChannelGroup 房间广播
RoomChannelGroup roomGroup = rooms.get(roomId);
for (Channel ch : roomGroup) {
ch.writeAndFlush(frame); // frame 只编码一次
}2.2 消息压缩与频率
优化手段:
增量状态(只发变化字段)
定点数/变长编码(见协议优化)
LZ4 压缩(批量消息)
时间窗聚合(高频小消息合并,见协议优化章节)
频率控制:
广播频率上限(如 10Hz 状态同步)
上行输入限频(防刷,见反脚本章节)三、房间内帧同步
3.1 服务器 Tick
帧同步核心(状态同步版):
服务器固定 Tick(如 10 次/秒)驱动对局
每 Tick:收集本帧输入 → 计算 → 广播状态
Tick 实现:
ScheduledExecutorService 固定频率
或 Netty HashedWheelTimer
对局内事件处理(输入收集)与 Tick 计算串行// Tick 主循环
public void onTick(long frame) {
List inputs = collectInputs(frame); // 本帧输入列表
world.step(inputs, DELTA_TIME); // 物理步进
StateDiff diff = world.diff(lastState); // 增量
broadcast(diff, frame); // 广播
saveSnapshotEvery(SNAPSHOT_FREQ); // 快照
}3.2 输入队列与校正
输入处理:
客户端输入带序列号(防乱序)
服务器按序处理(同玩家串行)
延迟补偿:缓冲若干帧输入(见帧同步章节)
校正与回放:
客户端本地预测 → 服务器状态回来校正
大偏差 → 快照回滚
快照:每 N 帧全量状态(Redis 存储)
重连:拉最近快照恢复// 快照恢复(断线重连)
byte[] snap = snapshotStore.load(roomId, lastFrame);
if (snap != null) {
send(snap); // 全量快照
sendPendingDiffs(since); // 之后的增量
}四、AOI 视野管理
4.1 兴趣区域算法
AOI(Area of Interest):
只向"看得见"的玩家广播实体变化
大幅降低广播量(大场景必备)
实现方案:
网格法:场景划分格子,维护玩家所在格 + 九宫格邻居
十字链表:按 x/y 有序链表,范围查询
九宫格广播:玩家移动 → 进/出格子 → 订阅/取消邻居
本项目(弹射竞技场):
网格法(场景固定大小,格子划分简单)// 网格 AOI 订阅
Set enter = grid.getEnterers(player, newPos); // 新视野内玩家
Set leave = grid.getLeavers(player, newPos); // 移出视野玩家
for (Long id : enter) { sendEnterEntity(id); subscribe(id); }
for (Long id : leave) { sendLeaveEntity(id); unsubscribe(id); }4.2 广播降噪
AOI 收益:
大场景实体广播量降为 O(视野) 而非 O(全场)
视野外实体:只发"进入视野"事件,不发细节
与房间广播配合:
房间内小场景(≤8 人)→ 直接房间广播
大场景(多人竞技场)→ AOI 广播
按玩法配置广播模式五、实现要点
实时对战(上)清单:
选型:弹射对战 → 状态同步(服务端权威)
广播:ChannelGroup 房间广播 + 增量压缩
帧同步:固定 Tick + 输入队列 + 快照恢复
AOI:网格法视野管理 + 广播降噪
常见坑:
广播全量状态 → 带宽爆(用增量)
Tick 内阻塞(锁/DB)→ 帧抖动
只预测不校正 → 客户端显示漂移
小场景也上 AOI → 过度设计(按玩法配置)
下篇预告:
匹配池 + 分布式分片 + 弹性伸缩 + 反外挂 + 全链路监控