Releases: iohao/ioGame
java netty 集群游戏服务器框架 ioGame 17.1.28
增加版本标识
增加版本标识,并在 DebugInOut 插件中显示的打印。
┏━━━━━ Debug. [(HelloAction.java:88).world] ━━━ [cmd:1 - subCmd:7 - cmdMerge:65543] ━━━ [逻辑服 [hello 游戏逻辑服] - id:[fc3348f8-4881-49e4-b94d-8cd99ab543cf]]
┣ userId: 0
┣ 参数: helloReq : HelloReq(name=112)
┣ 响应: HelloReq(name=死亡阴影3)
┣ 时间: 0 ms (业务方法总耗时)
┗━━━━━ Debug [HelloAction.java - ioGame:17.1.28] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
业务框架处理器
增加 ActionCommandTryHandler 并作为默认的业务框架处理器。
业务框架默认是在 bolt 线程运行,如果有异常会被 bolt 捕获到日志文件中。由于控制台没有显示的打印异常信息,开发者如果对 bolt 不熟悉,是不知道有该日志文件的。当出现异常时,将会浪费开发人员的时间来排查问题,为了避免这种情况,业务框架先做捕获,并打印到控制台中,在向上抛 ex。
bolt 日志文件相关 https://www.yuque.com/iohao/game/derl0laiu2v0k104#likQv
final class ActionCommandTryHandler extends ActionCommandHandler {
@Override
public boolean handler(final FlowContext flowContext) {
/*
* 业务框架默认是在 bolt 线程运行,如果有异常会被 bolt 捕获到日志文件中,
* https://www.yuque.com/iohao/game/derl0laiu2v0k104#likQv
*
* 由于没有打印到控制台,开发者如果对 bolt 不熟悉,是不会看日志文件,或者说不知道有该日志文件。
* 为了避免这种情况,业务框架先做捕获并打印,在向上抛 ex
*
*/
try {
return super.handler(flowContext);
} catch (Throwable e) {
log.error(e.getMessage(), e);
throw e;
}
}
}
java netty 分布式游戏服务器框架 ioGame 17.1.27
#27
业务框架与网络通信框架解耦
新增 ChannelContext 通信通道接口,用于对 bolt AsyncContext、netty Channel 的包装,这样可以使得业务框架与网络通信框架解耦,为将来 ioGame 实现绳量级架构的使用做准备。
移除 FlowAttr.asyncContext 动态属性,由 FlowAttr.channelContext 代替。
业务框架模块移除网络相关的依赖 bolt、netty 等。
#28
游戏对外服 netty 编排业务钩子接口
新增 ChannelPipelineHook netty 业务编排的处理器钩子接口,用于游戏对外服。
ExternalServerBuilder 新增 channelPipelineHook 属性 ,用于自定义 netty 业务编排的处理器设置。
废弃标记 ExternalServerBuilder.channelHandlerProcessors 属性及其相关地方为过期,由 ChannelPipelineHook 来代替,使用示例如下。
public class ExternalServerBuilderApplication {
public static void main(String[] args) {
// netty ChannelHandler 编排
var myChannelPipelineHook = new ChannelPipelineHook() {
@Override
public void initChannelPipeline(ChannelPipeline pipeline) {
pipeline.addLast("ExternalBizHandler", new ExternalBizHandler());
// pipeline.addFirst("ssl", ssl)
}
};
// 游戏对外服构建器
ExternalServerBuilder builder = ExternalServer.newBuilder(10100);
builder.channelPipelineHook(myChannelPipelineHook);
}
}
通常情况下,这样的编排方式也会更加清晰,因为代码统一在这里做编排了。开发者在自定义业务编排时,可以通过这个钩子接口,比如添加一个 SSL。
注意事项:在调用 hook 前,会经过 ExternalChannelInitializerCallback.initChannelPipeline(SocketChannel) ,
ExternalChannelInitializerCallback 接口的实现类有
- ExternalChannelInitializerCallbackWebsocket
- ExternalChannelInitializerCallbackTcp
这些实现类中,会给 ChannelPipeline 添加上一些默认的处理器,通常是编解码相关的。
在处理 action 时,我们可以通过 FlowContext.userId 可以很方便得到当前用户(玩家)id。
如果开发者想在处理 action 时,携带上一些自定义的信息时,可以通过元附加信息特性来完成。比如保存当前玩家的英雄角色 id,或者玩家的昵称,又或者是你的项目的 userId 是 string 或其他类型则可以通过元信息这一特性来兼容。
简单的说,就是你想在 FlowContext 中获取一些用户(玩家)特有的信息数据时,可以通过这个特性来实现。
// 自定义一个元信息类,实现 Attachment 元附加信息接口
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class MyAttachment implements Attachment {
@Getter
long userId;
String nickname;
}
@ActionController(1)
public class DemoAction {
@ActionMethod(1)
public void attachment(FlowContext flowContext) {
// 创建自定义的元附加信息对象
MyAttachment myAttachment = new MyAttachment();
myAttachment.userId = flowContext.getUserId();
myAttachment.nickname = "英雄无敌3";
// 设置元信息 ----- 关键代码
ExternalCommunicationKit.setAttachment(myAttachment);
}
@ActionMethod(2)
public MyAttachment printAttachment(FlowContext flowContext) {
// 得到元信息,这个是在上面的方法中设置的元信息对象
var attachment = flowContext.getAttachment(MyAttachment.class);
return attachment;
}
}
通过这个示例可以看出,元信息的设置与获取是简单的。
甚至你还可以配合自定义 FolwContext 特性 ,对这个扩展做更符合项目的定制,如下
// 自定义一个元信息类,实现 Attachment 元附加信息接口
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class MyAttachment implements Attachment {
@Getter
long userId;
String nickname;
}
public class MyFlowContext extends FlowContext {
public String getNickname() {
var attachment = this.getAttachment(MyAttachment.class);
return attachment.nickname;
}
}
@ActionController(1)
public class DemoAction {
@ActionMethod(1)
public void attachment(MyFlowContext flowContext) {
// 创建自定义的元附加信息对象
MyAttachment myAttachment = new MyAttachment();
myAttachment.userId = flowContext.getUserId();
myAttachment.nickname = "英雄无敌3";
// 设置元信息 ----- 关键代码
ExternalCommunicationKit.setAttachment(myAttachment);
}
@ActionMethod(3)
public void printAttachment(MyFlowContext flowContext) {
var nickname = flowContext.getNickname();
System.out.println(nickname);
}
}
其他优化
命令解析器与源码文档逻辑分离。
优化命令对象,减少 action 类的实例化对象
java websocket 游戏服务器框架 ioGame 17.1.25 多协议支持 protobuf、json
v17.1.25 news
ActionCommandInfoBuilder 改名为 ActionCommandParser 命令解析器
将业务框架中的部分类设置为 final 权限
废弃动态属性 FlowAttr.data ,由 FlowAttr.actionBizParam 代替
#I63L7V BarSkeletonBuilderParamConfig 类的方法名变更
addActionController 标记为废弃,请使用 scanActionPackage。
addActionSend 标记为废弃,请使用 scanActionSendPackage。
因为 addActionController 、addActionSend 的方法名,会给部分开发者带来混淆。这导致部分开发者在使用时 addActionController 方法时,会多次添加 action 类。实际上只需要随意配置一个 action 类就可以了,即使有一万个action。
#I63L89 标准 action 规则
- 业务方法上添加注解 ActionMethod
- 业务方法的访问权限必须是:public
- 业务方法不能是:static
- 业务方法需要是在 action 类中声明的方法
简单的说,标准的 action 是非静态的,且访问权限为 public 的方法。
术语说明:在 action 类中提供的业务方法通常称为 action
#I6307A 支持多种协议:protobuf、json,并支持可扩展
现在 ioGame 支持同样的一套业务代码,无需开发者做代码的变更,就能支持多种协议的切换,如:protobuf、json。协议的切换是简单的,只需要一行代码。
简单点说,如果开发者的项目之前使用的是 json 数据来传输的,以后想改用 protobuf 来传输,是不需要改变业务方法的。框架除了内置支持的 protobuf、json 协议外,开发者还可以对协议进行扩展。
让我们先看一个 action 的业务代码片段。
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class HelloReq {
String name;
}
@ActionController(19)
public class JsonAction {
@ActionMethod(1)
public HelloReq hello(HelloReq helloReq) {
helloReq.name = helloReq.name + ",hello json";
return helloReq;
}
}
似乎与之前介绍的并没有什么区别,至少在编写代码方式上没什么区别。在不变更代码的情况下,就能支持 json 数据协议了。
在 ioGame 中切换协议是简单的,只需要一行代码。ioGame 默认的 json 编解码器使用的是 fastjson2 来解析 json 数据,如果开发者想使用其他 json 库来做数据解析,可以通过扩展的方式,并且扩展是简单的、容易的。
public class JsonApplication {
public static void main(String[] args) {
// 设置 json 编解码。如果不做设置,默认使用 jprotobuf
IoGameGlobalSetting.me().setDataCodec(new JsonDataCodec());
// 游戏对外服端口
int port = 10100;
// 逻辑服
var demoLogicServer = new JsonLogicServer();
// 启动 对外服、网关服、逻辑服; 并生成游戏业务文档
SimpleHelper.run(port, List.of(demoLogicServer));
}
}