【游戏】低帧率策略游戏类帧同步保障公平性软件详细设计文档

低帧率策略游戏类帧同步保障公平性软件详细设计文档

版本 :v1.0

文档状态 :正式版

适用项目 :多人在线即时策略游戏(类星际争霸)

核心设计原则:服务器权威(Server-Authoritative)、确定性帧同步(Deterministic Lockstep)、公平性优先(Fairness First)

1. 引言

1.1 目的

本文档定义了一款低帧率(<20 FPS)多人在线即时策略游戏 的帧同步网络架构设计方案。该方案旨在通过服务器权威 + 类锁步等待机制,在保证所有玩家绝对公平竞技的前提下,兼顾网络抖动容忍度和断线恢复能力。

1.2 适用范围

  • 游戏逻辑帧率:< 20 帧/秒(每帧 50ms)
  • 玩家规模:2 ~ 10 人
  • 网络模型:纯服务器权威,客户端仅负责渲染与控制指令发送
  • 赛事等级:支持从娱乐局到职业局域网比赛的多级配置

1.3 设计约束

  • 客户端不参与任何游戏逻辑计算,仅作为状态渲染终端
  • 游戏引擎(服务器进程)单一实例运行,不存在分布式共识
  • 逻辑计算必须具备确定性(Deterministic),以支持断线恢复后的快照加载
  • 不采用 AI 托管,掉线玩家直接阻塞引擎,由外部裁判系统裁决

2. 系统架构概览

2.1 整体拓扑

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                     赛事大厅 / 裁判系统                          │
│              (匹配、裁决、超时监测、判负指令)                    │
└─────────────┬───────────────────────────────────┬───────────────┘
              │ 管理指令通道                       │ 管理指令通道
              ▼                                   ▼
┌─────────────────────────────────────────────────────────────────┐
│                  游戏引擎(权威服务器)                           │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  主线程(计算线程): 帧循环 + 条件等待 + 状态广播         │   │
│  │  管理线程(指令监听): 接收判负/继续等待指令              │   │
│  └─────────────────────────────────────────────────────────┘   │
│  内存状态: 当前帧完整快照 + 环形缓冲区(近30帧历史快照)         │
└─────────────┬───────────────────────────────────┬───────────────┘
              │ 控制指令通道                       │ 状态推送通道
              ▼                                   ▼
┌─────────────────────┐                 ┌─────────────────────────┐
│   客户端 A           │                 │   客户端 B ... N         │
│  • 指令采集与上报     │                 │  • 指令采集与上报         │
│  • 状态接收与渲染     │                 │  • 状态接收与渲染         │
│  • 重连与快照加载     │                 │  • 重连与快照加载         │
└─────────────────────┘                 └─────────────────────────┘

2.2 模块职责

模块 职责
游戏引擎(Engine) 帧推进、逻辑计算、状态快照维护、状态广播
等待调度器(Wait Scheduler) 阻塞等待所有玩家指令,支持条件变量中断
快照管理器(Snapshot Manager) 环形缓冲区维护最近N帧完整状态,响应重连拉取
管理指令处理器(Admin Command Processor) 接收并执行"判负/继续等待"等管理指令
裁判系统(Referee System) 超时监测、裁决逻辑、裁判人工操作界面
客户端(Client) 指令采集上报、状态接收渲染、重连协议

3. 核心机制设计

3.1 帧同步基础模型

3.1.1 帧与帧号
  • 游戏以固定时间步长(50ms)推进,每步称为一帧(Frame)
  • 帧号从 0 开始单调递增,永不回退
  • 所有逻辑计算(单位移动、攻击、生产等)均在帧边界执行
3.1.2 确定性要求

由于客户端重连时加载的是"计算好的状态快照"而非"重放指令序列",服务器单实例计算不存在跨平台浮点不一致问题。但以下场景仍需保证确定性:

  • 录像回放(Replay):如果未来支持,需确保相同输入序列产生相同输出
  • 单元测试:相同种子下的逻辑回归测试
  • 实现方式 :禁用 std::rand(),使用确定性线性同余生成器(LCG);禁用 double,统一使用 int64_t 定点数表示坐标与血量

3.2 帧推进等待机制(核心公平性保障)

3.2.1 基本流程
复制代码
服务器推进至第 N 帧后,进入第 N+1 帧准备阶段:
  1. 检查所有存活玩家是否已提交"第 N+1 帧"的控制指令
  2. 若未收齐 → 进入阻塞等待(Wait)状态
  3. 若收齐 → 执行第 N+1 帧逻辑,广播状态变更,推进至 N+1
3.2.2 客户端指令上报规范
  • 客户端必须**每帧(每 50ms)**主动上报指令,即使无操作也必须发送"空指令(Null Input)"
  • 上报数据包必须包含:
    • req_frame:客户端期望服务器计算的下一帧号
    • ack_frame:客户端已确认接收并渲染的最新帧号
    • input_mask:本帧操作位掩码(按键/鼠标状态)
  • 上报通道:控制指令通道,采用可靠有序的流式传输(如 TCP 长连接),客户端异步非阻塞发送
3.2.3 等待条件变量唤醒

主线程等待采用条件变量(Condition Variable) + 双重唤醒条件

复制代码
wait_until(
    all_inputs_received() OR admin_interrupt_signal()
)
  • 输入唤醒:所有玩家针对当前待计算帧的指令均已到达
  • 管理唤醒:外部裁判系统发来"判负/继续等待"指令

3.3 最大超前帧数(Max Ahead Frames)

3.3.1 机制定义

引擎允许服务器当前计算帧与最慢玩家确认帧(ack_frame)之间的最大差值

  • 设服务器当前帧为 current_frame,玩家 P 的确认帧为 ack_frame[P]
  • current_frame - ack_frame[P] >= max_ahead_frames,则引擎停止推进,等待该玩家
  • 该参数为静态配置,在比赛开始时确定,中途不可变更
3.3.2 分级配置标准
比赛等级 max_ahead_frames 等效缓冲时间 适用场景
娱乐/路人局 30 ~ 60 1.5 ~ 3.0 秒 容忍WiFi波动,降低重连频率
线上排位(天梯) 10 0.5 秒 兼顾公平与流畅
线上职业赛 2 0.1 秒 吸收网络丢包重传,近乎绝对同步
线下局域网赛 0 0 秒 绝对锁步,一人卡全员停
3.3.3 工作原理图示
复制代码
时间线(服务器视角):
帧:  1000   1001   1002   ...   1020   1021
      ↑       ↑       ↑            ↑      ↑
     快玩家确认帧:  1000   1001   1002  1020   (正常推进)
     慢玩家确认帧:  1000   1000   1000  1000   (卡在1000帧)
     
若 max_ahead_frames = 20:
  当服务器计算到 1020 帧时,检查发现 1020 - 1000 = 20 ≥ 20
  → 引擎暂停,等待慢玩家追上

3.4 快照管理(Snapshots & Delta)

3.4.1 双通道推送策略
通道 协议特征 内容 触发条件
状态变更通道 不可靠但低延迟广播(如 UDP 组播或 PUB 模式) 本帧发生变化的实体(增量) 每帧正常广播
快照通道 可靠单播传输(如 TCP 请求-响应) 完整的游戏世界状态(全量) 客户端重连请求
3.4.2 环形缓冲区(Ring Buffer)
  • 服务器内存中维护一个 容量为 30 帧的环形缓冲区
  • 每帧计算完成后,将当前帧完整状态序列化存入缓冲区
  • 缓冲区索引:buffer[frame_id % 30] = serialize(world)
  • 用途:响应重连客户端的"拉取最新帧"请求,且可提供最近30帧的任意帧快照(用于调试或未来扩展)
3.4.3 重连快照拉取协议
复制代码
客户端重连请求:
  → 携带 client_last_ack_frame(客户端本地确认的最新帧号)
  → 服务器忽略该数值,直接返回 buffer[latest_frame % 30](最新完整快照)
  → 客户端加载快照,覆盖所有本地状态
  → 客户端设置 ack_frame = latest_frame,继续上报后续帧指令

设计决策:不追溯中间帧,不做增量回放。断线玩家直接"时空跳跃"至当前最新状态。

4. 指令与状态同步详细流程

4.1 正常帧循环(无人掉线)

复制代码
┌──────┐     ┌──────────────┐     ┌──────────┐     ┌──────────────┐
│客户端│     │控制指令通道  │     │  引擎    │     │状态推送通道  │
└──┬───┘     └──────┬───────┘     └────┬─────┘     └──────┬───────┘
   │                │                    │                  │
   │ 每50ms上报     │                    │                  │
   │───────────────>│                    │                  │
   │ req_frame=N+1  │                    │                  │
   │ ack_frame=N    │                    │                  │
   │ input=...      │                    │                  │
   │                │  存入待处理队列     │                  │
   │                │───────────────────>│                  │
   │                │                    │  检查是否收齐    │
   │                │                    │  所有玩家指令    │
   │                │                    │  (是)            │
   │                │                    │                  │
   │                │                    │  执行 tick(N+1)  │
   │                │                    │  计算 Delta      │
   │                │                    │──────────────────>│
   │                │                    │                  │  广播Delta
   │                │                    │                  │─────────>客户端
   │                │                    │  存入快照        │
   │                │                    │  buffer[N+1]    │
   │                │                    │                  │
   │                │                    │  N = N+1        │
   │                │                    │                  │
   │                │  继续下一轮        │                  │
   │<───────────────│───────────────────│                  │
   │                │                    │                  │

4.2 阻塞等待场景(某玩家指令未到)

复制代码
时间: T0          T0+100ms      T0+200ms      T0+500ms
帧:   1000         等待中          等待中         收到指令 → 1001
      │             │              │              │
引擎主线程         检查发现玩家A  条件变量阻塞   玩家A重连后提交
 执行第1000帧  →  的指令未到  →  等待唤醒    →  指令, 条件变量
  逻辑完成         进入等待状态                   触发唤醒
                     │              │              │
其他玩家:           画面定格       画面定格       画面恢复流畅
画面正常            (卡顿开始)     (持续卡顿)     (卡顿结束)

4.3 裁判判负干预流程

复制代码
┌──────────┐      ┌──────────────┐      ┌──────────┐
│ 裁判系统 │      │ 引擎管理线程 │      │ 引擎主线程│
└────┬─────┘      └──────┬───────┘      └────┬─────┘
     │                   │                    │
     │ 检测到玩家A超时   │                    │ 主线程阻塞在
     │ (例如120秒无响应) │                    │ wait_condition
     │                   │                    │
     │ 裁判点击"判负"    │                    │
     │──────────────────>│                    │
     │  判负指令(A)      │                    │
     │                   │  收到管理指令       │
     │                   │  设置中断标志       │
     │                   │  唤醒条件变量      │
     │                   │───────────────────>│
     │                   │                    │ 主线程醒来
     │                   │                    │ 检查中断标志
     │                   │                    │ 执行处理管理指令
     │                   │                    │   → 移除玩家A
     │                   │                    │   → 清除A所有单位
     │                   │                    │ 回到循环首
     │                   │                    │ 检查存活玩家
     │                   │                    │ 指令已收齐
     │                   │                    │ 继续推进
     │                   │                    │

5. 通信通道设计

5.1 通道分类与职责

通道名称 方向 传输特征 内容描述
控制指令通道 客户端 → 服务器 可靠、有序、流式 每帧上报玩家操作指令(含空指令)
状态推送通道 服务器 → 客户端 不可靠、低延迟、广播 每帧推送游戏状态变更(Delta)
快照通道 客户端 ↔ 服务器 可靠、请求-响应 重连时拉取完整世界状态快照
管理指令通道 裁判系统 → 服务器 可靠、优先级高 判负、继续等待等管理指令

5.2 控制指令通道协议规范

5.2.1 数据包结构
复制代码
┌──────────────┬──────────────┬──────────────┬──────────────┐
│   帧号       │   确认帧号   │   操作掩码   │   校验和     │
│   (int32)    │   (int32)    │   (uint32)   │   (uint16)   │
└──────────────┴──────────────┴──────────────┴──────────────┘
5.2.2 传输要求
  • 保证按序到达(同一连接内的消息顺序与发送顺序一致)
  • 保证可靠到达(丢失重传机制)
  • 客户端每帧定时发送,不受用户操作影响

5.3 状态推送通道协议规范

5.3.1 Delta 消息格式
json 复制代码
{
    "frame": 1001,
    "timestamp": 1734567890123,
    "deltas": [
        {"entity_id": 101, "field": "hp", "value": 85},
        {"entity_id": 102, "field": "position", "x": 12.5, "y": 34.2},
        {"entity_id": 103, "field": "state", "value": "attacking"}
    ],
    "removed_entities": [104, 105]
}
5.3.2 传输要求
  • 允许丢包(客户端重连时通过快照通道补偿)
  • 低延迟优先于可靠性
  • 广播方式发送,无需客户端确认

5.4 快照通道协议规范

5.4.1 请求格式
json 复制代码
{
    "player_id": 1,
    "client_last_frame": 980
}
5.4.2 响应格式
json 复制代码
{
    "current_frame": 1020,
    "serialized_world": "<base64编码的完整游戏状态>",
    "compressed": true
}
5.4.3 传输要求
  • 可靠传输(TCP 或等效协议)
  • 大块数据传输支持压缩
  • 单次请求-响应模式

5.5 管理指令通道协议规范

5.5.1 指令类型
指令类型 参数 说明
DECLARE_DEFEAT target_player_id 宣告某玩家失败,清除其所有单位
CONTINUE_WAIT target_player_id, duration_ms 裁判决定继续等待指定时长
FORCE_ADVANCE target_player_id 强制推进(仅调试模式)
QUERY_STATUS 查询引擎当前状态
5.5.2 传输要求
  • 可靠性极高(命令丢失不可接受)
  • 具有权限验证机制(仅裁判系统可发送)
  • 实时性要求高于普通控制指令

6. 引擎模块详细设计

6.1 主线程(计算线程)伪代码

cpp 复制代码
class GameEngine {
public:
    void Run() {
        while (is_running_) {
            // ========== 阶段1: 等待所有玩家输入 ==========
            InputCollection inputs;
            bool is_admin_interrupted = false;
            
            // 条件变量等待,双重唤醒条件
            {
                std::unique_lock<std::mutex> lock(wait_mutex_);
                wait_cv_.wait(lock, [this, &inputs, &is_admin_interrupted]() {
                    // 条件1: 所有存活玩家已提交待计算帧的指令
                    if (IsAllInputsReady(current_frame_ + 1)) {
                        inputs = CollectInputs(current_frame_ + 1);
                        return true;
                    }
                    // 条件2: 管理线程发来中断信号
                    if (admin_interrupt_flag_) {
                        is_admin_interrupted = true;
                        return true;
                    }
                    return false;
                });
            }
            
            // ========== 阶段2: 处理外部管理指令 ==========
            if (is_admin_interrupted) {
                ProcessAdminCommands();  // 可能移除玩家、判负等
                admin_interrupt_flag_ = false;
                continue;  // 回到循环开始,重新检查输入条件
            }
            
            // ========== 阶段3: 执行逻辑帧 ==========
            // 执行第 current_frame_ + 1 帧
            world_.Tick(inputs);
            current_frame_++;
            
            // ========== 阶段4: 更新广播与快照 ==========
            // 计算 Delta
            Delta delta = world_.CollectDelta();
            state_push_channel_.Send(delta.Serialize());
            
            // 存储完整快照到环形缓冲区
            snapshot_buffer_[current_frame_ % BUFFER_SIZE] = world_.Serialize();
            
            // 等待下一帧(50ms - 实际耗时)
            SleepUntilNextFrameTick();
        }
    }
    
private:
    std::condition_variable wait_cv_;
    std::mutex wait_mutex_;
    std::atomic<bool> admin_interrupt_flag_{false};
    std::queue<AdminCommand> admin_command_queue_;
    
    int32_t current_frame_ = 0;
    int32_t max_ahead_frames_ = 20;   // 可配置
    SnapshotBuffer snapshot_buffer_;
    World world_;
};

6.2 管理线程(指令监听)伪代码

cpp 复制代码
class AdminCommandHandler {
public:
    void OnAdminCommand(const AdminCommand& cmd) {
        std::lock_guard<std::mutex> lock(engine_->wait_mutex_);
        
        switch (cmd.type) {
        case AdminCommand::DECLARE_DEFEAT:
            // 将判负指令入队
            engine_->admin_command_queue_.push({
                .type = CommandType::kDeclareDefeat,
                .target_player = cmd.target_player_id
            });
            break;
            
        case AdminCommand::CONTINUE_WAIT:
            // 延长等待,不做任何状态变更,仅记录日志
            LOG(INFO) << "裁判指令: 继续等待玩家 " << cmd.target_player_id;
            break;
            
        case AdminCommand::FORCE_ADVANCE:
            // 调试模式专用,谨慎使用
            engine_->admin_command_queue_.push({
                .type = CommandType::kForceAdvance,
                .target_player = cmd.target_player_id
            });
            break;
        }
        
        // 唤醒主线程
        engine_->admin_interrupt_flag_ = true;
        engine_->wait_cv_.notify_one();
    }
};

6.3 判负处理逻辑

cpp 复制代码
void GameEngine::ProcessAdminCommands() {
    while (!admin_command_queue_.empty()) {
        AdminCommand cmd = admin_command_queue_.front();
        admin_command_queue_.pop();
        
        switch (cmd.type) {
        case CommandType::kDeclareDefeat: {
            Player* player = FindPlayer(cmd.target_player);
            if (player && player->IsAlive()) {
                // 1. 标记玩家为失败状态
                player->SetState(PlayerState::kDefeated);
                
                // 2. 执行游戏内清除逻辑(所有单位爆炸/消失)
                world_.KillAllUnitsBelongingTo(player->id());
                
                // 3. 从等待列表移除(不再等待该玩家的指令)
                active_players_.erase(player->id());
                
                LOG(INFO) << "玩家 " << player->id() << " 被裁判判负,已清除所有单位";
            }
            break;
        }
        case CommandType::kForceAdvance:
            // 强制推进:注入空指令给掉线玩家
            // 仅在调试/开发模式允许
            if (config_.allow_force_advance) {
                InjectDefaultInputsForLaggingPlayers();
            }
            break;
        }
    }
}

6.4 最大超前帧数检查逻辑

cpp 复制代码
bool GameEngine::IsAllInputsReady(int32_t frame_id) {
    for (const auto& player : active_players_) {
        // 检查该玩家是否已提交 frame_id 的指令
        if (!player.HasSubmittedInput(frame_id)) {
            // 检查是否已触发 max_ahead_frames 上限
            int32_t lag_frames = current_frame_ - player.ack_frame();
            if (lag_frames >= config_.max_ahead_frames) {
                // 超过上限,触发等待状态
                // 这里不直接返回false,而是让主线程进入阻塞等待
                // 同时由外部裁判系统监测超时并干预
                LOG(WARNING) << "玩家 " << player.id() 
                             << " 落后 " << lag_frames 
                             << " 帧,已达到上限 " << config_.max_ahead_frames
                             << ",引擎即将阻塞等待";
                return false;
            }
        }
    }
    // 所有玩家都已提交指令,或落后的玩家尚未达到上限
    return true;
}

7. 异常处理与边界情况

7.1 玩家主动退出

场景 处理方式
玩家点击"退出/认输" 客户端通过控制指令通道发送退出请求 → 引擎标记该玩家为失败 → 清除其单位 → 继续推进(无需等待其指令)
玩家强制关闭进程 无退出请求 → 引擎检测到指令超时 → 进入阻塞等待 → 外部裁判系统超时判负

7.2 客户端重连

复制代码
重连流程:
  1. 客户端检测到状态推送通道超时(收不到 Delta 超过 2 秒)
  2. 客户端通过快照通道发起重连请求
  3. 服务器返回 snapshot_buffer_[current_frame_ % BUFFER_SIZE]
  4. 客户端清空本地所有游戏对象,反序列化快照
  5. 客户端设置 ack_frame = server.current_frame
  6. 客户端继续正常上报 req_frame = ack_frame + 1 的指令
  7. 服务器检测到该玩家重新加入活跃列表,继续等待其指令
  8. 若快照拉取失败(网络原因),客户端可重试,引擎继续等待

7.3 裁判系统超时阈值配置

比赛等级 引擎等待超时阈值(裁判判负触发) 说明
娱乐局 120 秒 给予充足时间重启路由器
排位赛 60 秒 容忍短暂网络波动
职业线上 30 秒 选手需在30秒内重连
职业线下 无限(由裁判人工控制) 裁判现场判断,不受自动超时约束

7.4 环形缓冲区满覆盖处理

  • 缓冲区容量固定为 30 帧
  • frame_id % 30 的位置已有数据时,直接覆盖(旧帧不再需要)
  • 若重连客户端请求的帧号比 current_frame_ - 30 更早,返回错误码 ERR_FRAME_TOO_OLD,客户端只能拉取最新帧

8. 配置参数汇总

8.1 引擎配置文件 (server_config.yaml)

yaml 复制代码
game:
  tick_rate_hz: 20
  max_ahead_frames: 20          # 默认1秒缓冲
  snapshot_buffer_size: 30      # 环形缓冲区容量

channels:
  control_channel_port: 50051
  state_push_channel_port: 5556
  snapshot_channel_port: 50052
  admin_channel_port: 50053

referee:
  mode: hybrid                   # auto / manual / hybrid
  auto_timeout_seconds: 120      # 自动化超时判负阈值
  allow_force_advance: false     # 是否允许调试强制推进

logging:
  level: info
  enable_frame_trace: false      # 仅调试时开启

8.2 赛事等级预设配置

yaml 复制代码
# 预设1: 娱乐局
preset_casual:
  max_ahead_frames: 60
  auto_timeout_seconds: 120

# 预设2: 排位赛
preset_ranked:
  max_ahead_frames: 10
  auto_timeout_seconds: 60

# 预设3: 线上职业赛
preset_tournament_online:
  max_ahead_frames: 2
  auto_timeout_seconds: 30

# 预设4: 线下局域网赛
preset_tournament_lan:
  max_ahead_frames: 0
  auto_timeout_seconds: 0       # 由裁判人工操作,自动超时禁用

9. 接口定义

9.1 客户端 → 引擎(控制指令通道)

接口 方向 说明
ReportInput(stream InputRequest) 客户端流式 → 引擎 每帧上报玩家操作指令
RequestSnapshot(SnapshotRequest) 客户端 → 引擎 重连时拉取完整快照
RequestQuit(QuitRequest) 客户端 → 引擎 主动退出/认输

数据契约

json 复制代码
InputRequest:
{
    "player_id": 1,
    "req_frame": 1001,
    "ack_frame": 1000,
    "input_mask": 0x0000000A
}

SnapshotRequest:
{
    "player_id": 1,
    "client_last_frame": 980
}

SnapshotResponse:
{
    "current_frame": 1020,
    "serialized_world": "<binary data>"
}

9.2 裁判系统 → 引擎(管理指令通道)

接口 方向 说明
SendAdminCommand(AdminRequest) 裁判系统 → 引擎 发送判负/继续等待等指令
GetEngineStatus(Empty) 裁判系统 → 引擎 查询引擎运行状态
GetFrameSnapshot(FrameRequest) 裁判系统 → 引擎 调试用,拉取指定帧快照

数据契约

json 复制代码
AdminRequest:
{
    "type": "DECLARE_DEFEAT | CONTINUE_WAIT | FORCE_ADVANCE",
    "target_player_id": 1,
    "wait_duration_ms": 30000
}

EngineStatus:
{
    "current_frame": 1020,
    "player_count": 8,
    "waiting_for_player": 3,
    "state": "RUNNING | WAITING | FINISHED"
}

9.3 引擎 → 客户端(状态推送通道)

复制代码
主题/分类: delta.{frame_id}
内容: 
{
    "frame": 1001,
    "timestamp": 1734567890123,
    "deltas": [...],
    "removed_entities": [...]
}

10. 未来扩展考虑

扩展方向 设计兼容性说明
录像回放(Replay) 当前架构已保存每帧完整状态快照,录像只需存储所有帧的输入序列 + 随机种子即可重放
观战模式(Spectator) 观战客户端可订阅状态推送通道,拉取最新帧快照初始化,无需提交指令
P2P 模式备选 若后续需要支持客户端建房(无服务器),可参考替代方案(如 GameNetworkSockets + ICE),作为本方案的并行模式
断线重连历史回放 当前为"最新帧快照"策略,未来若希望断线玩家看到中间过程,可将环形缓冲区容量扩展并支持增量回放链

11. 术语表

术语 定义
帧(Frame) 游戏逻辑的最小时间单位,固定 50ms
Delta 本帧相对于上一帧发生变化的实体状态集合(增量)
Snapshot 某一帧的完整游戏世界状态(全量)
最大超前帧数(Max Ahead Frames) 服务器允许领先最慢客户端确认帧的最大帧数差值
确定性(Deterministic) 相同输入序列 + 相同随机种子在任何环境产生相同输出的性质
条件变量(Condition Variable) 线程同步原语,用于阻塞等待特定条件满足
服务器权威(Server-Authoritative) 所有关键逻辑计算仅在服务器执行,客户端仅作为展示端
环形缓冲区(Ring Buffer) 固定大小的循环队列,新数据覆盖旧数据
裁判系统(Referee System) 独立于引擎的外部服务,负责超时监测、判负裁决、人工操作界面
指令(Input) 玩家在单帧内的操作集合,包含键盘/鼠标状态位掩码
控制指令通道(Control Channel) 客户端到服务器的指令上报通道,可靠有序传输
状态推送通道(State Push Channel) 服务器到客户端的状态广播通道,允许丢包,低延迟优先
相关推荐
比兔代理1 小时前
代理IP池性能瓶颈在哪?并发、带宽与IP质量的平衡优化策略
服务器·网络·tcp/ip·安全
BlueAsia_Lab1 小时前
Wi‑Fi 认证:企业办理需要准备哪些资料?
运维·服务器·网络
恋恋西风1 小时前
TCP 三次握手 / 四次挥手 讲解
网络·网络协议·tcp/ip
Horn Still Sounds2 小时前
Linux网络编程|UDP与TCP传输层协议深度梳理
linux·网络·tcp/ip·udp
比兔代理2 小时前
动态 IP 代理深度讲解:IP 地址轮换机制与会话保持方案
网络·网络协议·tcp/ip
蕾米莉亚《'';2 小时前
科普向host和port(感谢千问
网络
玫幽倩2 小时前
2025MoeCTF(Pwn全)
网络·安全·pwn·ctf·新生赛·二进程·moectf
rcms152702692183 小时前
Novellus 27-033321-00 涡轮分子泵
网络
薛定e的猫咪3 小时前
(IEEE Transactions 2025)自适应元强化学习动态柔性作业车间调度框架
网络·人工智能·算法