访问游戏对外服与扩展
介绍
访问游戏对外服与扩展,是框架提供的通讯方式之一,主要用于游戏逻辑服与游戏对外服的交互上。
本篇介绍如何从游戏对外服中获取我们需要的数据。
ExternalBizRegion 接口
ExternalBizRegion 接口是用于游戏对外服业务扩展,开发者通过实现这个接口,可以向游戏逻辑服提供一些,如
- 只存在于游戏对外服中的数据
 - 只有游戏对外服可以做的事
 
框架通过这一扩展,轻松实现了如下功能;
- ExistUserExternalBizRegion 查询用户(玩家)是否在线,类似重复登录的检测
 - ForcedOfflineExternalBizRegion 强制用户(玩家)下线,类似顶号的功能
 - AttachmentExternalBizRegion 元附加信息
 - 获取玩家 ip
 
如何扩展
实现 ExternalBizRegion 接口,并将编写好的实现类添加到 ExternalBizRegions 中
ExternalBizRegions.add(new YourExternalBizRegion());
示例
现在,我们通过一个示例来说明该接口的使用,该示例是从游戏对外服中获取在线玩家的 userId。
Example Source Code
see https://github.com/iohao/ioGameExamples
path : SimpleExample/example/example-external-biz-region
自定义 ExternalBizRegion 扩展类
OnlineUserExternalBizRegion 是 ExternalBizRegion 接口的扩展类。 类的内容比较简单,收集在线玩家的 userId。
public class OnlineUserExternalBizRegion implements ExternalBizRegion {
    @Override
    public int getBizCode() {
        // custom business codes
        // cn: 自定义业务码
        return MyExternalBizCode.onlineUser;
    }
    @Override
    public Serializable request(ExternalBizRegionContext regionContext) {
        OnlineUser onlineUser = new OnlineUser();
        regionContext.getUserSessions().forEach(userSession -> {
            long userId = userSession.getUserId();
            onlineUser.getUserIds().add(userId);
        });
        return onlineUser;
    }
}
@Data
public class OnlineUser implements Serializable {
    List<Long> userIds = new ArrayList<>();
}
public interface MyExternalBizCode {
    int onlineUser = 1;
}
配置
将实现类添加到 ExternalBizRegions 中。
public class ExternalBizRegionApplication {
    public static void main(String[] args) {
        ExternalBizRegions.add(new OnlineUserExternalBizRegion());
        ...
    }
}
使用
我们在 action 示例中触发 OnlineUserExternalBizRegion 相关逻辑。
- listOnlineUser 方法演示了访问玩家所在的【游戏对外服】
 - listOnlineUserAll 方法演示了访问多个【游戏对外服】
 
@ActionController(ExternalBizRegionCmd.cmd)
public class ExternalBizRegionAction {
    ...
    @ActionMethod(ExternalBizRegionCmd.listOnlineUser)
    public List<Long> listOnlineUser(FlowContext flowContext) {
        var collectExternalMessage = flowContext.invokeExternalModuleCollectMessage(MyExternalBizCode.onlineUser);
        return listUserId(collectExternalMessage);
    }
    @ActionMethod(ExternalBizRegionCmd.listOnlineUserAll)
    public List<Long> listOnlineUserAll(FlowContext flowContext) {
        var request = flowContext.createRequestCollectExternalMessage(MyExternalBizCode.onlineUser);
        var collectExternalMessage = flowContext.invokeExternalModuleCollectMessage(request);
        return listUserId(collectExternalMessage);
    }
    static List<Long> listUserId(ResponseCollectExternalMessage collectExternalMessage) {
        List<Long> userIdList = new ArrayList<>();
        for (ResponseCollectExternalItemMessage itemMessage : collectExternalMessage.getMessageList()) {
            // OnlineUserExternalBizRegion 所返回的数据
            OnlineUser onlineUser = itemMessage.getData();
            List<Long> userIds = onlineUser.getUserIds();
            log.info("userIds : {}", userIds);
            userIdList.addAll(userIds);
        }
        return userIdList;
    }
}
小结
只要想象力足够,通过 ExternalBizRegion 接口可以做很多事。
通过扩展 ExternalBizRegion 接口,可以获取游戏对外服中的任何数据, flowContext.invokeExternalModuleCollectMessage 方法会向所有的游戏对外服发起请求。
在调用端的使用很简单,通过通讯上下文就可以调用了, 更多使用示例可以参考工具类 ExternalCommunicationKit。
如果游戏对外服、broker(游戏网关)、游戏逻辑服是分开部署的, 需要在 pom 中分别引入这个自定义的扩展类,因为 Serializable 会涉及到几个服务器之间的传输。
扩展阅读
访问指定的游戏对外服
默认情况下,广播会给所有的游戏对外服发送消息,因为我们的架构是支持启动多个游戏对外服的,你也可以手动设置需要访问的游戏对外服。
...
var requestCollectExternalMessage = new RequestCollectExternalMessage()
    .setBizCode(yourExternalBizCode)
    .setSourceClientId(sourceClientId);
BrokerClientHelper
    .getInvokeExternalModuleContext()
    .invokeExternalModuleCollectMessage(requestCollectExternalMessage);