Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • 架构设计

    • 架构概述
    • BigWorld 架构深度解析
    • BigWorld 进程架构与玩家生命周期
  • AOI 系统

    • AOI九宫格系统详解
    • AOI广播与消息去重

BigWorld 进程架构与玩家生命周期

目录

  • BigWorld 进程架构图
  • 进程间通信关系
  • 玩家登录流程
  • 玩家游戏流程
  • 玩家对战流程
  • 玩家聊天流程
  • 玩家下线流程

BigWorld 进程架构图

整体架构

┌─────────────────────────────────────────────────────────────────────────────┐
│                              客户端 (Client)                                 │
│                    Unity/Unreal/WebGL + 网络层                               │
└────────────────────────────┬────────────────────────────────────────────────┘
                             │ TCP/WebSocket
                             ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           LoginApp (登录服务器)                              │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌────────────┐              │
│  │  认证模块  │  │ 网关分配   │  │  负载均衡  │  │ 会话令牌生成 │              │
│  └───────────┘  └───────────┘  └───────────┘  └────────────┘              │
│  职责: 处理登录认证、分配网关、创建初始会话                                    │
└────────────────────────────┬────────────────────────────────────────────────┘
                             │ 返回网关地址 + 会话令牌
                             ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                         GatewayApp (网关服务器)                              │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌────────────┐              │
│  │ 连接管理   │  │ 消息路由   │  │  心跳检测  │  │  流量控制   │              │
│  └───────────┘  └───────────┘  └───────────┘  └────────────┘              │
│  职责: 维持客户端连接、路由消息到后端、防止攻击                                │
└────────┬──────────────────────────────┬─────────────────────────────────────┘
         │                              │
         │ 游戏逻辑消息                  │ 聊天消息
         ▼                              ▼
┌──────────────────────────┐  ┌──────────────────────────┐
│    BaseApp (数据库服务器)  │  │    ChatApp (聊天服务器)   │
│  ┌───────────┐            │  │  ┌───────────┐           │
│  │ 数据库连接池 │           │  │  │ 频道管理   │           │
│  │ ORM映射    │            │  │  │ 消息广播   │           │
│  │ 缓存管理   │            │  │  │ 敏感词过滤 │           │
│  │ 异步加载   │            │  │  │ 历史记录   │           │
│  └───────────┘            │  │  └───────────┘           │
│  职责: 玩家数据CRUD、缓存  │  │  职责: 聊天频道、广播    │
└────────┬─────────────────┘  └──────────────────────────┘
         │
         │ 分配/加载实体
         ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                        CellApp 游戏逻辑服务器集群                            │
│                                                                              │
│  ┌───────────────┐  ┌───────────────┐  ┌───────────────┐                    │
│  │  CellApp #1   │  │  CellApp #2   │  │  CellApp #N   │                    │
│  │  (主城区域)   │  │  (野外区域)   │  │  (副本区域)   │                    │
│  ├───────────────┤  ├───────────────┤  ├───────────────┤                    │
│  │ AOI系统       │  │ AOI系统       │  │ AOI系统       │                    │
│  │ 实体管理      │  │ 实体管理      │  │ 实体管理      │                    │
│  │ 战斗逻辑      │  │ 战斗逻辑      │  │ 战斗逻辑      │                    │
│  │ 技能系统      │  │ 技能系统      │  │ 技能系统      │                    │
│  │ NPC AI       │  │ NPC AI       │  │ NPC AI       │                    │
│  │ 跨边界同步    │  │ 跨边界同步    │  │ 跨边界同步    │                    │
│  └───────────────┘  └───────────────┘  └───────────────┘                    │
│                                                                              │
│  职责: 游戏核心逻辑、AOI视野管理、实体状态更新、跨区域迁移                     │
└─────────────────────────────────────────────────────────────────────────────┘
                             ▲
                             │ 数据保存/加载
                    ┌────────┴────────┐
                    │   数据库集群      │
                    │ MySQL + Redis    │
                    └─────────────────┘

进程职责总结

进程缩写核心职责通信对象
LoginApp登录服务器认证、网关分配Client, BaseApp
GatewayApp网关服务器连接管理、消息路由Client, CellApp, ChatApp, BaseApp
BaseApp数据库服务器数据CRUD、缓存GatewayApp, CellApp, Database
CellApp游戏逻辑服务器游戏逻辑、AOI、战斗GatewayApp, 其他CellApp
ChatApp聊天服务器聊天频道、广播GatewayApp

进程间通信关系

通信拓扑图

                    ┌─────────────┐
                    │   Database  │
                    │  (MySQL)    │
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐        ┌─────────────┐
         ┌──────────│   BaseApp   │◄───────│  LoginApp   │
         │          └──────┬──────┘        └──────┬──────┘
         │                 │                      │
         │                 │                      │
┌────────┴────────┐   ┌────▼────┐          ┌────▼────┐
│     Client      │   │GatewayApp│          │GatewayApp│
│  (Unity/Unreal) │◄──┤  Pool    │◄─────────┤  Pool    │
└────────┬────────┘   └────┬────┘          └────┬────┘
         │                 │                      │
         │        ┌────────┴────────┐   ┌────────┴────────┐
         │        │  ┌─────┬─────┐  │   │  ┌─────┬─────┐  │
         └───────►│  │ C#1 │ C#2 │...│   │  │ C#N │...  │  │
                  │  └──┬──┴──┬──┘  │   │  └──┬──┴────┘  │
                  └─────┼─────┼─────┘   └─────┼──────────┘
                        │     │               │
                        └──┬──┴───────┬───────┘
                           │          │
                    ┌──────▼─────┐    │
                    │  ChatApp   │    │
                    └────────────┘    │
                          ▲           │
                          └───────────┘

    Legend:
    C#N = CellApp #N
    ───► 消息流向
    ◄──── 同步/返回

玩家登录流程

流程图

Client                    LoginApp                BaseApp                GatewayApp              CellApp
  │                          │                       │                       │                       │
  │ 1. 连接请求               │                       │                       │                       │
  ├─────────────────────────►│                       │                       │                       │
  │                          │                       │                       │                       │
  │ 2. 登录请求(账号/密码)     │                       │                       │                       │
  ├─────────────────────────►│                       │                       │                       │
  │                          │                       │                       │                       │
  │                          │ 3. 验证账号密码        │                       │                       │
  │                          ├──────────────────────►│                       │                       │
  │                          │                       │                       │                       │
  │                          │ 4. 返回玩家数据        │                       │                       │
  │                          │◄──────────────────────┤                       │                       │
  │                          │                       │                       │                       │
  │                          │ 5. 查找最优Gateway    │                       │                       │
  │                          ├──────────────────────────────────────────────►│                       │
  │                          │                       │                       │                       │
  │                          │ 6. 返回Gateway地址    │                       │                       │
  │                          │◄──────────────────────────────────────────────┤                       │
  │                          │                       │                       │                       │
  │ 7. 返回网关地址+会话令牌   │                       │                       │                       │
  │◄─────────────────────────┤                       │                       │                       │
  │                          │                       │                       │                       │
  │ 8. 断开与LoginApp的连接   │                       │                       │                       │
  ├─────────────────────────✘│                       │                       │                       │
  │                          │                       │                       │                       │
  │ 9. 连接到GatewayApp      │                       │                       │                       │
  ├─────────────────────────────────────────────────────────────────────────►│                       │
  │                          │                       │                       │                       │
  │ 10. 进入游戏请求(令牌)    │                       │                       │                       │
  ├─────────────────────────────────────────────────────────────────────────►│                       │
  │                          │                       │                       │                       │
  │                          │ 11. 验证令牌           │                       │                       │
  │                          ├──────────────────────►│                       │                       │
  │                          │                       │                       │                       │
  │                          │ 12. 加载完整玩家数据   │                       │                       │
  │                          │◄──────────────────────┤                       │                       │
  │                          │                       │                       │                       │
  │                          │ 13. 分配目标CellApp   │                       │                       │
  │                          ├──────────────────────────────────────────────────────────────────────►│
  │                          │                       │                       │                       │
  │                          │ 14. 创建玩家实体       │                       │                       │
  │                          │◄──────────────────────────────────────────────────────────────────────┤
  │                          │                       │                       │                       │
  │ 15. 返回登录成功          │                       │                       │                       │
  │◄─────────────────────────────────────────────────────────────────────────┤                       │
  │                          │                       │                       │                       │
  │ 16. 开始接收游戏世界数据  │                       │                       │                       │
  │◄═════════════════════════════════════════════════════════════════════════╪═══════════════════════►│
                           │                       │                       │                       │
                           └── 登录流程完成 ─────────┘                       │                       │

代码示例

// LoginApp 处理登录
class LoginApp {
    Response handleLogin(const LoginRequest& req) {
        // 1. 验证账号密码
        auto playerData = baseApp_->verifyAccount(req.username, req.password);
        if (!playerData) {
            return Response::Error("账号或密码错误");
        }

        // 2. 查找最优Gateway (负载最低的)
        auto gateway = gatewayManager_->selectBestGateway();

        // 3. 生成会话令牌
        std::string token = generateSessionToken(playerData->id);

        // 4. 记录会话
        sessionManager_->createSession(token, playerData->id, gateway->address());

        return LoginSuccessResponse{
            .gatewayAddress = gateway->address(),
            .gatewayPort = gateway->port(),
            .sessionToken = token
        };
    }
};

// GatewayApp 处理进入游戏
class GatewayApp {
    Response handleEnterGame(const EnterGameRequest& req, Connection* conn) {
        // 1. 验证令牌
        auto session = loginApp_->verifySession(req.token);
        if (!session) {
            return Response::Error("无效的会话令牌");
        }

        // 2. 从BaseApp加载完整玩家数据
        auto playerData = baseApp_->loadPlayerData(session->playerId);
        if (!playerData) {
            return Response::Error("加载玩家数据失败");
        }

        // 3. 根据玩家位置分配CellApp
        auto cellApp = cellAppManager_->assignByPosition(playerData->lastPosition);

        // 4. 在CellApp中创建玩家实体
        auto entity = cellApp_->createPlayerEntity(*playerData);

        // 5. 创建Proxy (客户端连接代理)
        auto proxy = createProxy(conn, entity->id());

        // 6. 关联Proxy和CellApp
        proxy->bindToCellApp(cellApp);

        return EnterGameSuccessResponse{
            .entityId = entity->id(),
            .position = playerData->lastPosition
        };
    }
};

玩家游戏流程

游戏主循环消息流

Client                    GatewayApp                CellApp
  │                          │                       │
  │ 1. 移动请求               │                       │
  ├─────────────────────────►│                       │
  │                          │                       │
  │                          │ 2. 转发到CellApp       │
  │                          ├──────────────────────►│
  │                          │                       │
  │                          │                       │ 3. 验证移动合法性
  │                          │                       │ 4. 更新位置
  │                          │                       │ 5. 计算AOI变化
  │                          │                       │
  │                          │                       │ 6. 发现新玩家进入视野
  │                          │                       │    ┌──────────────────┐
  │                          │                       │    │ EntityAppear{e1} │
  │                          │◄──────────────────────┤    │ EntityAppear{e2} │
  │ 7. 周围实体出现           │                       │    └──────────────────┘
  │◄─────────────────────────┤                       │
  │                          │                       │
  │                          │                       │ 8. 广播给周围玩家
  │                          │                       │    ┌──────────────────┐
  │                          │                       │    │ EntityMove{me}   │
  │                          │                       │    └──────────────────┘
  │                          │                       │
  │                          │ 9. 转发给其他Gateway   │
  │                          ├─────────────────────────────────────────►
  │                          │                       │
  │ 10. 其他客户端看到移动    │                       │
  │◄═════════════════════════════════════════════════╪═══════════════════════╪═══════════════════

CellApp 内部处理

// CellApp 处理玩家移动
class CellApp {
    void handleMove(EntityID entityId, Position newPos) {
        Entity* entity = getEntity(entityId);
        if (!entity) return;

        Position oldPos = entity->position();

        // 1. 验证移动合法性
        if (!validateMove(entity, oldPos, newPos)) {
            return; // 非法移动,忽略
        }

        // 2. 更新位置
        entity->setPosition(newPos);

        // 3. 检查是否跨格子
        if (getGridId(oldPos) != getGridId(newPos)) {
            handleCrossGridMove(entity, oldPos, newPos);
        }

        // 4. 检查是否跨CellApp
        if (!bounds_.contains(newPos)) {
            handleCrossCellAppMove(entity, newPos);
            return; // 实体已迁移
        }

        // 5. 计算AOI变化
        auto viewChange = aoi_->calculateViewChange(oldPos, newPos);

        // 6. 通知离开视野的玩家
        for (auto* leaver : viewChange.leavers) {
            gateway_->sendToClient(leaver->clientId, EntityLeaveMsg{entityId});
        }

        // 7. 通知进入视野的玩家
        for (auto* enterer : viewChange.enterers) {
            gateway_->sendToClient(enterer->clientId, EntityAppearMsg{entityId, newPos});
        }

        // 8. 广播移动给一直在视野内的玩家
        for (auto* stayer : viewChange.stayers) {
            gateway_->sendToClient(stayer->clientId, EntityMoveMsg{entityId, oldPos, newPos});
        }
    }
};

玩家对战流程

战斗消息流

Client A (攻击者)         GatewayApp              CellApp              Client B (目标)
  │                          │                       │                       │
  │ 1. 释放技能请求           │                       │                       │
  ├─────────────────────────►│                       │                       │
  │                          │                       │                       │
  │                          │ 2. 转发技能请求        │                       │
  │                          ├──────────────────────►│                       │
  │                          │                       │                       │
  │                          │                       │ 3. 验证技能
  │                          │                       │ 4. 计算伤害
  │                          │                       │ 5. 扣除血量
  │                          │                       │                       │
  │                          │                       │ 6. B收到伤害事件
  │                          │                       │    ┌────────────────┐
  │                          │                       │    │ EntityDamage   │
  │                          │                       │    │ hp: 100→80     │
  │ 7. B受到伤害通知          │                       │    └────────────────┘
  │◄═════════════════════════════════════════════════╪═══════════════════════►│
  │                          │                       │                       │
  │                          │                       │ 8. 播放特效
  │                          │                       │ 9. 广播伤害结果
  │                          │                       │    ┌────────────────┐
  │                          │                       │    │ SkillHitResult │
  │ 10. 周围玩家看到伤害      │                       │    └────────────────┘
  │◄═════════════════════════════════════════════════╪═══════════════════════►│
  │                          │                       │                       │
  │                          │                       │ 11. 如果B死亡
  │                          │                       │    ┌────────────────┐
  │                          │                       │    │ EntityDeath    │
  │                          │                       │    └────────────────┘
  │ 12. 看到B死亡             │                       │                       │
  │◄═════════════════════════════════════════════════╪════════════════════════════════════════════►│
  │                          │                       │                       │

跨CellApp战斗

CellApp A                 CellApp B
(边界附近)                (边界附近)
  │                          │
  │                          │
  │ A区玩家攻击B区目标        │
  │                          │
  │ 1. 在A创建目标的Shadow    │
  │ ◄───────────────────────►│
  │                          │
  │ 2. 计算伤害(A)           │
  │                          │
  │ 3. 同步伤害结果到B        │
  ├─────────────────────────►│
  │                          │
  │                          │ 4. 应用伤害(B)
  │                          │
  │ 5. 同步死亡事件           │
  │◄────────────────────────►│
  │                          │
  ▼                          ▼

战斗代码示例

// CellApp 处理技能释放
class CellApp {
    void handleCastSkill(EntityID casterId, uint32_t skillId, EntityID targetId) {
        Entity* caster = getEntity(casterId);
        Entity* target = getEntity(targetId);

        if (!caster || !target) return;

        // 1. 验证技能条件
        if (!caster->canCastSkill(skillId)) {
            return; // CD中、蓝量不足等
        }

        // 2. 验证目标在射程内
        float distance = calcDistance(caster->position(), target->position());
        if (distance > getSkillRange(skillId)) {
            return; // 超出射程
        }

        // 3. 计算伤害
        int32_t damage = calculateDamage(caster, target, skillId);

        // 4. 应用伤害
        applyDamage(caster, target, damage);

        // 5. 触发技能特效
        spawnSkillEffect(skillId, target->position());

        // 6. 广播技能释放
        aoi_->broadcastToViewers(caster, SkillCastMsg{
            .casterId = casterId,
            .skillId = skillId,
            .targetId = targetId
        });

        // 7. 广播伤害结果
        aoi_->broadcastToViewers(target, SkillHitMsg{
            .targetId = targetId,
            .damage = damage,
            .currentHp = target->hp()
        });

        // 8. 检查死亡
        if (target->hp() <= 0) {
            handleEntityDeath(target);
        }
    }

    void applyDamage(Entity* attacker, Entity* target, int32_t damage) {
        // 如果目标在其他CellApp (边界情况)
        if (target->isShadow()) {
            // 转发伤害到目标所属CellApp
            target->ownerCellApp()->receiveRemoteDamage(target->id(), damage);
        } else {
            // 本地实体,直接应用
            target->takeDamage(damage);
        }
    }
};

玩家聊天流程

聊天消息流

Client A                  GatewayApp                ChatApp                Client B
  │                          │                       │                       │
  │ 1. 发送聊天消息           │                       │                       │
  │   /say 你好              │                       │                       │
  ├─────────────────────────►│                       │                       │
  │                          │                       │                       │
  │                          │ 2. 验证会话            │                       │
  │                          │ 3. 检查禁言状态        │                       │
  │                          │                       │                       │
  │                          │ 4. 转发到ChatApp      │                       │
  │                          ├──────────────────────►│                       │
  │                          │                       │                       │
  │                          │                       │ 5. 敏感词过滤
  │                          │                       │ 6. 查找频道成员
  │                          │                       │                       │
  │                          │                       │ 7. 确定接收者
  │                          │                       │    ┌──────────────┐
  │                          │                       │    │ A: "你好"     │
  │ 8. 广播给频道成员          │                       │    └──────────────┘
  │◄═════════════════════════════════════════════════╪═══════════════════════►│
  │                          │                       │                       │

聊天频道类型

频道类型范围ChatApp处理示例
当前频道AOI内玩家查询CellApp获取AOI内玩家/say 你好
世界频道全服玩家查询所有在线玩家/world 求组
私聊频道指定玩家查询目标玩家所在Gateway/tell Player 消息
公会频道公会成员查询公会成员列表/guild 打BOSS
队伍频道队伍成员查询队伍成员/party 集合
// ChatApp 处理聊天
class ChatApp {
    void handleChatMessage(const ChatMessage& msg) {
        // 1. 验证发送者
        Player* sender = getPlayer(msg.senderId);
        if (!sender || sender->isMuted()) {
            return; // 玩家不存在或被禁言
        }

        // 2. 敏感词过滤
        std::string filtered = filterSensitiveWords(msg.content);

        // 3. 根据频道类型分发
        switch (msg.channel) {
            case Channel::CURRENT: {
                // 当前频道:发送给AOI内玩家
                auto viewers = cellApp_->getAOIViewers(sender->position());
                broadcastToPlayers(viewers, ChatMsg{
                    .sender = sender->name(),
                    .content = filtered,
                    .channel = Channel::CURRENT
                });
                break;
            }
            case Channel::WORLD: {
                // 世界频道:发送给全服玩家
                auto allPlayers = getAllOnlinePlayers();
                broadcastToPlayers(allPlayers, ChatMsg{
                    .sender = sender->name(),
                    .content = filtered,
                    .channel = Channel::WORLD
                });
                break;
            }
            case Channel::PRIVATE: {
                // 私聊:发送给指定玩家
                Player* receiver = getPlayerByName(msg.targetName);
                if (receiver) {
                    sendToPlayer(receiver, ChatMsg{
                        .sender = sender->name(),
                        .content = filtered,
                        .channel = Channel::PRIVATE
                    });
                }
                break;
            }
            case Channel::GUILD: {
                // 公会频道:发送给公会成员
                auto guildMembers = guildManager_->getMembers(sender->guildId());
                broadcastToPlayers(guildMembers, ChatMsg{
                    .sender = sender->name(),
                    .content = filtered,
                    .channel = Channel::GUILD
                });
                break;
            }
        }

        // 4. 记录聊天历史 (用于审计)
        chatHistory_->record(msg.senderId, msg.channel, filtered);
    }
};

玩家下线流程

正常下线

Client                    GatewayApp                CellApp                BaseApp
  │                          │                       │                       │
  │ 1. 请求退出游戏           │                       │                       │
  ├─────────────────────────►│                       │                       │
  │                          │                       │                       │
  │                          │ 2. 通知CellApp下线     │                       │
  │                          ├──────────────────────►│                       │
  │                          │                       │                       │
  │                          │                       │ 3. 广播玩家离开
  │                          │                       │    ┌──────────────┐
  │ 4. 周围玩家看到离开       │                       │    │ EntityLeave  │
  │◄═════════════════════════════════════════════════╪═════════════════════►│
  │                          │                       │                       │
  │                          │                       │ 5. 销毁玩家实体       │
  │                          │                       │                       │
  │                          │ 6. 保存玩家数据        │                       │
  │                          ├──────────────────────────────────────────────►│
  │                          │                       │                       │
  │                          │                       │                       │ 7. 写入数据库
  │                          │                       │                       │   更新Redis缓存
  │                          │                       │                       │
  │                          │ 8. 保存完成            │                       │
  │                          │◄──────────────────────────────────────────────┤
  │                          │                       │                       │
  │ 9. 下线成功               │                       │                       │
  │◄─────────────────────────┤                       │                       │
  │                          │                       │                       │
  │ 10. 断开连接              │                       │                       │
  ├─────────────────────────✘│                       │                       │

异常掉线处理

Client                    GatewayApp                CellApp                BaseApp
  │                          │                       │                       │
  │ 1. 网络断开/超时         │                       │                       │
  ├─────────────────────────✘│                       │                       │
  │                          │                       │                       │
  │                          │ 2. 检测到连接断开      │                       │
  │                          │    (心跳超时)          │                       │
  │                          │                       │                       │
  │                          │ 3. 启动安全下线流程     │                       │
  │                          │    (保留实体N秒)       │                       │
  │                          ├──────────────────────►│                       │
  │                          │                       │                       │
  │                          │                       │ 4. 玩家进入"掉线保护"  │
  │                          │                       │    - 无法移动          │
  │                          │                       │    - 无敌状态          │
  │                          │                       │                       │
  │ 5a. 如果30秒内重连        │                       │                       │
  ├─────────────────────────►│                       │                       │
  │                          │ 6. 验证快速重连        │                       │
  │                          │ 7. 恢复连接            │                       │
  │                          │                       │                       │
  │                          │                       │ 8. 取消掉线保护       │
  │ ◄═════════════════════════════════════════════════╪═══════════════════════►│
  │                          │                       │                       │
  │                          │                       │                       │
  │ 5b. 如果30秒后未重连      │                       │                       │
  │                          │                       │ 9. 执行正常下线流程    │
  │                          │                       │                       │

下线代码示例

// GatewayApp 处理下线
class GatewayApp {
    void handleLogout(Connection* conn) {
        Proxy* proxy = getProxyByConnection(conn);
        if (!proxy) return;

        EntityID playerId = proxy->controlledEntity();

        // 1. 通知CellApp玩家下线
        cellApp_->onPlayerLogout(playerId);

        // 2. 异步保存数据 (不阻塞断开连接)
        baseApp_->savePlayerDataAsync(playerId, [this, conn](bool success) {
            // 保存完成后的回调
            if (!success) {
                logError("保存玩家数据失败");
            }
        });

        // 3. 立即断开连接
        conn->close();
    }

    // 处理异常掉线
    void onConnectionLost(Connection* conn) {
        Proxy* proxy = getProxyByConnection(conn);
        if (!proxy) return;

        EntityID playerId = proxy->controlledEntity();

        // 1. 启动掉线保护定时器
        timer_->setTimeout(30000, [this, playerId]() {
            // 30秒后检查是否重连
            if (!isPlayerReconnected(playerId)) {
                // 未重连,执行安全下线
                performSafeLogout(playerId);
            }
        });

        // 2. 通知CellApp进入掉线保护
        cellApp_->onPlayerDisconnect(playerId);
    }
};

// CellApp 处理掉线
class CellApp {
    void onPlayerDisconnect(EntityID playerId) {
        Entity* entity = getEntity(playerId);
        if (!entity) return;

        // 1. 标记为掉线保护状态
        entity->setFlag(EntityFlag::DISCONNECTED);
        entity->setInvincible(true);  // 无敌
        entity->setMovable(false);     // 不可移动

        // 2. 广播掉线状态 (可选显示"掉线中")
        aoi_->broadcastToViewers(entity, EntityStatusMsg{
            .entityId = playerId,
            .status = EntityStatus::DISCONNECTED
        });
    }

    void onPlayerReconnect(EntityID playerId, Proxy* newProxy) {
        Entity* entity = getEntity(playerId);
        if (!entity) return;

        // 1. 取消掉线保护
        entity->clearFlag(EntityFlag::DISCONNECTED);
        entity->setInvincible(false);
        entity->setMovable(true);

        // 2. 广播重连状态
        aoi_->broadcastToViewers(entity, EntityStatusMsg{
            .entityId = playerId,
            .status = EntityStatus::ONLINE
        });

        // 3. 同步当前状态给客户端
        newProxy->sendFullGameState(entity);
    }
};

完整玩家生命周期图

     注册                      登录                      游戏中                        下线
       │                        │                         │                           │
       ▼                        ▼                         ▼                           ▼
┌─────────────┐          ┌─────────────┐          ┌─────────────┐             ┌─────────────┐
│  Client注册  │          │ 连接LoginApp│          │  在CellApp   │             │ 正常/异常    │
│  账号创建    │          │ 验证账号密码 │          │  游戏循环     │             │  下线        │
└──────┬──────┘          └──────┬──────┘          └──────┬──────┘             └──────┬──────┘
       │                        │                         │                           │
       │ 数据存入               │ 返回Gateway地址          │                           │
       ▼ Database              ▼                         ▼                           ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│                        BaseApp (数据管理)                                           │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌───────────┐  ┌───────────┐        │
│  │ 创建账号   │  │ 验证登录   │  │ 加载数据   │  │ 定时保存   │  │ 最终保存   │        │
│  └───────────┘  └───────────┘  └───────────┘  └───────────┘  └───────────┘        │
└─────────────────────────────────────────────────────────────────────────────────────┘
       │                        │                         │                           │
       │                        │ 连接Gateway              │                           │
       │                        │ ▼                        │                           │
       │                        │ ┌───────────────────────────────────────────────┐   │
       │                        │ │              GatewayApp (连接管理)             │   │
       │                        │ │  ┌─────────┐  ┌─────────┐  ┌─────────┐       │   │
       │                        │ │  │ 验证令牌 │  │ 消息路由 │  │ 心跳检测 │       │   │
       │                        │ │  └─────────┘  └─────────┘  └─────────┘       │   │
       │                        │ └───────────────────────────────────────────────┘   │
       │                        │                         │                           │
       │                        │ 创建实体                 │                           │
       │                        │ ▼                        │                           │
       │                        │ ┌───────────────────────────────────────────────┐   │
       │                        │ │              CellApp (游戏逻辑)                │   │
       │                        │ │  ┌─────────┐  ┌─────────┐  ┌─────────┐       │   │
       │                        │ │  │ 实体管理 │  │ AOI系统 │  │ 战斗系统 │       │   │
       │                        │ │  │ 技能系统 │  │ NPC AI  │  │ 跨区迁移 │       │   │
       │                        │ │  └─────────┘  └─────────┘  └─────────┘       │   │
       │                        │ └───────────────────────────────────────────────┘   │
       │                        │                         │                           │
       │                        │ 聊天消息                 │                           │
       │                        │ ────────────────────────┼───────                    │
       │                        │                         ▼                           │
       │                        │              ┌─────────────────────┐                │
       │                        │              │     ChatApp         │                │
       │                        │              │  ┌───────────────┐  │                │
       │                        │              │  │ 频道管理       │  │                │
       │                        │              │  │ 消息广播       │  │                │
       │                        │              │  │ 敏感词过滤     │  │                │
       │                        │              │  └───────────────┘  │                │
       │                        │              └─────────────────────┘                │

总结

进程间协作模式

场景涉及进程协作方式
登录Client → LoginApp → GatewayApp → BaseApp → CellApp链式转发
移动Client → GatewayApp → CellApp直接路由
战斗Client → GatewayApp → CellApp ↔ CellApp直接路由 + 跨App同步
聊天Client → GatewayApp → ChatApp直接路由
下线GatewayApp → CellApp → BaseApp并行保存

关键设计要点

  1. GatewayApp是无状态的 - 可以水平扩展,负载均衡器随意分配
  2. CellApp按空间分割 - 玩家根据位置自动路由到对应CellApp
  3. BaseApp专注数据 - 异步处理数据库IO,不阻塞游戏逻辑
  4. ChatApp独立服务 - 聊天流量不影响游戏逻辑性能
  5. 掉线保护机制 - 给予玩家重连窗口,提升体验
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu
Prev
BigWorld 架构深度解析