ioGame 源码完全开放、最新文档阅读完全开放;使用完全自由、免费(遵守开源协议)。

ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。

文档与更新日志

 

https://github.com/iohao/ioGame/releases/tag/21.8

版本更新汇总

  • [light-game-room] #278 桌游类、房间类游戏的扩展模块,简化与规范化房间管理相关的、开始游戏流程相关的、玩法操作相关的相关扩展

  • [core] #290 新增广播文档构建器,简化生成广播对接文档

  • [示例集合整理] 将 SimpleExample(文档中所有功能点的示例)、SpringBootExample(综合示例)、ioGameWeb2Game(web 转游戏 – 示例理解篇)、fxglSimpleGame(移动同步 FXGL + netty)合并成一个示例项目。

[core]

#290 新增广播文档构建器,简化生成广播对接文档

下面是使用示例

 public class MyLogicServer extends AbstractBrokerClientStartup {     @Override     public BarSkeleton createBarSkeleton() {         // 业务框架构建器         BarSkeletonBuilder builder = ...                  // 错误码、广播、推送对接文档生成         extractedDco(builder);          return builder.build();     }          private void extractedDco(BarSkeletonBuilder builder) {         // 错误码         Arrays.stream(GameCode.values()).forEach(builder::addMsgExceptionInfo);          // UserCmd         builder.addBroadcastDoc(BroadcastDoc.newBuilder(UserCmd.of(UserCmd.enterSquare))                 .setDataClass(SquarePlayer.class)                 .setDescription("新玩家加入房间,给房间内的其他玩家广播")         ).addBroadcastDoc(BroadcastDoc.newBuilder(UserCmd.of(UserCmd.move))                 .setDataClass(SquarePlayerMove.class)                 .setDescription("其他玩家的移动")         ).addBroadcastDoc(BroadcastDoc.newBuilder(UserCmd.of(UserCmd.offline))                 .setDataClass(LongValue.class)                 .setDescription("有玩家下线了。userId")         );          // room         builder.addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.roomUpdateBroadcast))                 .setDataClass(FightRoomNotice.class)                 .setDescription("房间更新通知")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.playerEnterRoomBroadcast))                 .setDataClass(FightPlayer.class)                 .setDescription("有新玩家加入房间")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.enterRoom))                 .setDataClass(FightEnterRoom.class)                 .setDescription("玩家自己进入房间")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.dissolveRoomBroadcast))                 .setDescription("解散房间")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.quitRoom))                 .setDataClass(LongValue.class)                 .setDescription("有玩家退出房间了。userId")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.ready))                 .setDataClass(PlayerReady.class)                 .setDescription("有玩家准备或取消准备了")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.nextRoundBroadcast))                 .setDataClass(IntValue.class)                 .setDescription("对局开始,通知玩家开始选择。round 当前对局数")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.operationBroadcast))                 .setDataClass(LongValue.class)                 .setDescription("通知其他玩家,有玩家做了选择。userId")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.littleSettleBroadcast))                 .setDataClassList(FightRoundPlayerScore.class)                 .setDescription("广播玩家对局分数")         ).addBroadcastDoc(BroadcastDoc.newBuilder(RoomCmd.of(RoomCmd.gameOverBroadcast))                 .setDescription("游戏结束")         );     } }

 

其他扩展阅读

下面是生成后的对接文档预览

 ==================== 游戏文档格式说明 ==================== https://www.yuque.com/iohao/game/irth38#cJLdC  ==================== FightHallAction 大厅(类似地图) ==================== 路由: 1 - 1  --- 【登录】 --- 【FightHallAction:67】【loginVerify】     方法参数: LoginVerify loginVerify 登录验证     方法返回值: UserInfo 玩家信息   路由: 1 - 2  --- 【进入大厅】 --- 【FightHallAction:95】【enterSquare】     方法参数: EnterSquare enterSquare 进入大厅     方法返回值: ByteValueList<SquarePlayer> 所有玩家     广播推送: SquarePlayer 新玩家加入房间,给房间内的其他玩家广播   路由: 1 - 4  --- 【玩家移动】 --- 【FightHallAction:131】【move】     方法参数: SquarePlayerMove squarePlayerMove 玩家移动     方法返回值: void      广播推送: SquarePlayerMove 其他玩家的移动   路由: 1 - 5  --- 【玩家下线】 --- 【FightHallAction:155】【offline】     方法返回值: void      广播推送: LongValue 有玩家下线了。userId    ==================== FightRoomAction  ==================== 路由: 2 - 1  --- 【玩家创建新房间】 --- 【FightRoomAction:63】【createRoom】     方法返回值: void    路由: 2 - 2  --- 【玩家进入房间】 --- 【FightRoomAction:96】【enterRoom】     方法参数: LongValue roomId      房间号     方法返回值: void 房间信息     广播推送: FightEnterRoom 玩家自己进入房间   路由: 2 - 3  --- 【玩家退出房间】 --- 【FightRoomAction:120】【quitRoom】     方法返回值: void      广播推送: LongValue 有玩家退出房间了。userId   路由: 2 - 4  --- 【玩家准备】 --- 【FightRoomAction:146】【ready】     方法参数: BoolValue ready       true 表示准备,false 则是取消准备     方法返回值: void      广播推送: PlayerReady 有玩家准备或取消准备了   路由: 2 - 5  --- 【房间列表】 --- 【FightRoomAction:222】【listRoom】     方法返回值: ByteValueList<FightRoomNotice> 房间列表   路由: 2 - 6  --- 【玩家在游戏中的操作】 --- 【FightRoomAction:191】【operation】     方法参数: FightOperationCommand command     玩家操作数据     方法返回值: void    路由: 2 - 7  --- 【开始游戏】 --- 【FightRoomAction:162】【startGame】     方法返回值: void     ==================== 其它广播推送 ==================== 路由: 2 - 51  --- 广播推送: FightRoomNotice (房间更新通知) 路由: 2 - 50  --- 广播推送: FightPlayer (有新玩家加入房间) 路由: 2 - 52  --- 广播推送: IntValue (对局开始,通知玩家开始选择。round 当前对局数) 路由: 2 - 53  --- 广播推送: LongValue (通知其他玩家,有玩家做了选择。userId) 路由: 2 - 56  --- 广播推送: none (解散房间) 路由: 2 - 54  --- 广播推送: ByteValueList<FightRoundPlayerScore> (广播玩家对局分数) 路由: 2 - 55  --- 广播推送: none (游戏结束) ==================== 错误码 ====================  -1008 : 绑定的游戏逻辑服不存在   -1007 : 强制玩家下线   -1006 : 数据不存在   -1005 : class 不存在   -1004 : 请先登录   -1003 : 心跳超时相关   -1002 : 路由错误   -1001 : 参数验错误   -1000 : 系统其它错误   1 : 玩家在房间里   3 : 房间不存在   4 : 非法操作   6 : 开始游戏需要的最小人数不足   7 : 请等待其他玩家准备   8 : 房间空间不足,人数已满  

[light-game-room]

room 模块相关文档 – room 桌游、房间类 (yuque.com)

#278 桌游类、房间类游戏的扩展模块,简化与规范化房间管理相关的、开始游戏流程相关的、玩法操作相关的相关扩展

light-game-room 房间,是 ioGame 提供的一个轻量小部件 – 可按需选择的模块。

light-game-room + 领域事件 + 内置 Kit = 轻松搞定桌游类游戏

该模块是桌游类、房间类游戏的解决方案。比较适合桌游类、房间类的游戏基础搭建,基于该模型可以做一些如,炉石传说、三国杀、斗地主、麻将 …等类似的桌游。或者说只要是房间类的游戏,该模型都适用。比如,CS、泡泡堂、飞行棋、坦克大战 …等。

如果你计划做一些桌游类的游戏,那么推荐你基于该模块做扩展。该模块遵循面向对象的设计原则,没有强耦合,可扩展性强。且帮助开发者屏蔽了很多重复性的工作,并可为项目中的功能模块结构、开发流程等进行清晰的组织定义,减少了后续的项目维护成本。

主要解决的问题与职责

桌游、房间类的游戏在功能职责上可以分为 3 大类,分别是

  1. 房间管理相关的

    1. 管理着所有的房间、查询房间列表、房间的添加、房间的删除、房间与玩家之间的关联、房间查找(通过 roomId 查找、通过 userId 查找)。

  2. 开始游戏流程相关的

    1. 通常桌游、房间类的游戏都有一些固定的流程,如创建房间、玩家进入房间、玩家退出房间、解散房间、玩家准备、开始游戏 …等。

    2. 开始游戏时,需要做开始前的验证,如房间内的玩家是否符足够 …等,当一切符合业务时,才是真正的开始游戏。

  3. 玩法操作相关的

    1. 游戏开始后,由于不同游戏之间的具体操作是不相同的。如坦克的射击,炉石的战前选牌、出牌,麻将的吃、碰、杠、过、胡,回合制游戏的普攻、防御、技能 …等。

    2. 由于玩法操作的不同,所以我们的玩法操作需要是可扩展的,并用于处理具体的玩法操作。同时这种扩展方式更符合单一职责,使得我们后续的扩展与维护成本更低。

以上功能职责(房间管理相关、流程相关、玩法操作相关)属于相对通用的功能。如果每款游戏都重复的做这些工作,除了枯燥之外,还将浪费巨大的人力成本。

而当前模块则能很好的帮助开发者屏蔽这些重复性的工作,并可为项目中的功能模块结构、开发流程等进行清晰的组织定义,减少了后续的项目维护成本。更重要的是有相关文档,将来当你的团队有新进成员时,可以快速的上手。

room 实战简介

room 桌游、房间类实战(yuque.com)

文档中,我们基于该 room 模块做一个实战示例,该示例整体比较简单,多名玩家在房间里猜拳(石头、剪刀、布)得分。实战示例包括了前后端,前端使用 FXGL 引擎,这样开发者在学习时,只需 JDK 环境就可以了,而不需要安装更多的环境。启动游戏后玩家会将加入大厅(类似地图),多名玩家相互可见,并且玩家可以在大厅内移动。

下面是基于 room 模块的扩展实战 demo

[示例集合整理]

将 SimpleExample(文档中所有功能点的示例)、SpringBootExample(综合示例)、ioGameWeb2Game(web 转游戏 – 示例理解篇)、fxglSimpleGame(移动同步 FXGL + netty)合并成一个示例项目。

github gitee
ioGame 示例集合 ioGame 示例集合

 


 

ioGame 使用趋势数据

关注 ioGame 的游戏服务器开发者持续增多,2022-09 ~ 至今各月的统计数据;

这里的统计信息是关于开发者关注 ioGame 框架相关的,从统计数据中可以看出,由于 ioGame 上手简单,功能强大等优点,得到了众多开发者的关注。如果你想知道 ioGame 有没有人在使用,可以先到这里看下统计数据、开发者的评价与讨论。

https://www.yuque.com/iohao/game/gpxk93#TwVa8

这里展示了每月的统计数据,统计数据来源于语雀后台,这些数据都是真实的、客观存在的、活的

通过统计数据,我们可以看到每天会有很多开发者在访问 ioGame 的在线文档,并且这些统计数据不是来源于口嗨的,也不是主观创造的。

所以,还在犹豫要不要使用 ioGame 的开发者们,更应该讨论的是 “为什么这些开发者会选择使用 ioGame”,而不是 ioGame 有没有人在使用的问题。

点击我,到语雀后台查看 ioGame 的数据

netty 高性能游戏服务器框架;ioGame 21.8 真.轻量级网络编程框架发布插图


ioGame 网络游戏服务器框架简介

  • 无锁异步化、事件驱动的架构设计;轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式
  • 通过 ioGame 可以很容易的搭建出一个集群无中心节点、集群自动化、多进程的分布式游戏服务器
  • 包体小、启动快、内存占用少、更加的节约、无需配置文件、提供了优雅的路由访问权限控制
  • 可同时支持多种连接方式:WS、UDP、TCP… 等;框架已支持全链路调用日志跟踪特性
  • 让开发者用一套业务代码,能轻松切换和扩展不同的通信协议:Protobuf、JSON
  • 近原生的性能;业务框架在单线程中平均每秒可以执行 1152 万次业务逻辑
  • 代码即联调文档、JSR380 验证、断言 + 异常机制 = 更少的维护成本
  • 框架具备智能的同进程亲和性;开发中,业务代码可定位与跳转
  • 架构部署灵活性与多样性:既可相互独立,又可相互融合
  • 可同时与同类型的多个游戏逻辑服通信并得到数据
  • 逻辑服之间可相互跨进程、跨机器进行通信
  • 支持玩家对游戏逻辑服进行动态绑定
  • 能与任何其他框架做融合共存
  • 对 webMVC 开发者友好
  • 无 spring 强依赖
  • 零学习成本
  • javaSE

ioGame 的组成

ioGame 由 [网络通信框架] 和 [业务框架] 组成

  • 网络通信框架:职责是各服务器之间的网络通信
  • 业务框架:职责是业务逻辑的处理方式和编写方式

 

网络通信框架

SOFABolt 是蚂蚁金融服务集团开发的一套基于 Netty 实现的网络通信框架。

  • 为了让 Java 程序员能将更多的精力放在基于网络通信的业务逻辑实现上,而不是过多的纠结于网络底层 NIO 的实现以及处理难以调试的网络问题,Netty 应运而生。
  • 为了让中间件开发者能将更多的精力放在产品功能特性实现上,而不是重复地一遍遍制造通信框架的轮子,SOFABolt 应运而生。

Bolt 名字取自迪士尼动画 – 闪***,是一个基于 Netty 最佳实践的轻量、易用、高性能、易扩展的通信框架。

 

业务框架

如果说 sofa-bolt 是为了让 Java 程序员能将更多的精力放在基于网络通信的业务逻辑实现上。而业务框架正是解决业务逻辑如何方便实现这一问题上。业务框架是游戏框架的一部分,职责是简化程序员的业务逻辑实现,业务框架使程序员能够快速的开始编写游戏业务。

业务框架对于每个 action (即业务的处理方法) 都是通过 asm 与 Singleton、Flyweight 、Command 等设计模式结合,对 action 的获取上通过 array 来得到,是一种近原生的方式。

单线程中,业务框架平均每秒可以执行 1152 万次业务逻辑。


无锁异步化与事件驱动的架构设计、集群无中心节点、自带负载均衡、分布式支持、可动态增减机器、避免类爆炸的设计;

名称

扩展方式

职责

游戏对外服

分布式

与玩家连接、交互

游戏逻辑服

分布式

处理具体业务逻辑

Broker(游戏网关)

集群

调度和转发任务;


通过 ioGame 可以使得游戏编程变得简单,下面是一个业务示例

@ActionController(1)public class DemoAction {    @ActionMethod(0)    public HelloReq here(HelloReq helloReq) {        // 业务数据        var newHelloReq = new HelloReq();        newHelloReq.name = helloReq.name + ", I'm here ";        return newHelloReq;    }    // 注意,这个方法只是为了演示而写的;(ioGame21 开始支持)    // 效果与上面的方法一样,只不过是用广播(推送)的方式将数据返回给请求方@ActionMethod(0)    public void here(HelloReq helloReq, FlowContext flowContext) {        // 业务数据        var newHelloReq = new HelloReq();        newHelloReq.name = helloReq.name + ", I'm here ";        flowContext.broadcastMe(newHelloReq);    }    // 跨服调用示例,下面分别展示了同步与异步回调的写法    void testShowInvokeModule(FlowContext flowContext) {        /* * 框架为跨服请求提供了同步、异步、异步回调的编码风格 api。(ioGame21 开始支持) */        var cmdInfo = CmdInfo.of(1,0);        var yourData = ... 你的请求参数                // 跨服请求(异步回调 - 无阻塞)-- 路由、请求参数、回调。        flowContext.invokeModuleMessageAsync(cmdInfo, yourData, responseMessage -> {            var helloReq = responseMessage.getData(HelloReq.class);             // --- 此异步回调,具备全链路调用日志跟踪 ---            log.info("异步回调 : {}", helloReq);        });        // 跨服请求(同步 - 阻塞)-- 路由、请求参数。        ResponseMessage responseMessage = flowContext.invokeModuleMessage(cmdInfo, yourData);        var helloReq = responseMessage.getData(HelloReq.class);        log.info("同步调用 : {}", helloReq);    }}

 

有了以上信息,游戏开发者可以很快的定位问题。如果没有可视化的信息,开发中会浪费很多时间在前后端的沟通上。问题包括:

  • 是否传参问题 (游戏前端说传了)
  • 是否响应问题(游戏后端说返回了)
  • 业务执行时长问题 (游戏前端说没收到响应, 游戏后端说早就响应了)

其中代码导航可以让开发者快速的跳转到业务类对应代码中,在多人合作的项目中,可以快速的知道业务经过了哪些方法的执行,使得我们可以快速的进行阅读或修改;


框架内置的其他功能

内置多种可选模块,可按需选择,以方便应用开发:

  • 领域事件 轻量级单机最快 MQ — disruptor;通过领域事件模块,可为你的系统实现类似 Guava-EventBus、Spring 事件驱动模型 ApplicationEvent、业务解耦、规避并发、不阻塞主线程… 等,各种浪操作)
  • 任务延时器 (将来某个时间可对任务进行执行、暂停、取消等操作,并不是类似 Quartz 的任务调度)
  • 多环境切换 (不同运行环境下的配置支持)
  • light-jprotobuf 补足 jprotobuf 不能让多个对象在单个 .proto 源文件中生成的需求,并简化 jprotobuf 对源文件的注释
  • 分布式锁 (基于 Redisson 的简单实现)

内置的其他功能:


适合人群?

  1. 长期从事 web 内部系统开发人员, 想了解游戏的
  2. 刚从事游戏开发的
  3. 未从事过游戏开发,但却对其感兴趣的
  4. 对设计模式在实践中的应用和 sofa-bolt 有兴趣的学习者
  5. 可以接受新鲜事物的
  6. 想放弃祖传代码的

推荐实际编程经验一年以上的人员。

ioGame 提供了丰富的在线高质量使用文档,为你的团队助力,带上你们的小伙伴一起,这样就不用手把手的教了。

免责声明:本文系转载,版权归原作者所有;旨在传递信息,不代表一休教程网的观点和立场。