跳到主要内容

request/multiple_response

介绍

request/multiple_response,同时请求同类型多个游戏逻辑服,是框架提供的通讯方式之一。


框架支持启动多个相同的游戏逻辑服,比如 游戏逻辑服-B-1、游戏逻辑服-B-2

有时,我们需要同时访问多个相同游戏逻辑服的 action, 框架支持同时访问【同类型】的多个游戏逻辑服,并把多个相同游戏逻辑服的结果收集到一起。

下面,我们用一个示例来介绍。


使用场景举例

【象棋逻辑服】有 3 台,分别是:《象棋逻辑服-1》、《象棋逻辑服-2》、《象棋逻辑服-3》,这些游戏逻辑服可以在不同的进程中。

我们可以在大厅逻辑服中向【同类型】的多个游戏逻辑服请求,意思是大厅发起一个向这 3 台象棋逻辑服的请求, 框架会收集这 3 个结果集(假设结果是:当前服务器房间数)。

当大厅得到这个结果集,可以统计房间的总数,又或者说根据这些信息做一些其他的业务逻辑。这里只是举个例子,实际当中可以发挥自己的想象力。

An

Example Source Code

see https://github.com/iohao/ioGameExamples

path : SimpleExample/example/example-interaction-same

示例介绍

示例中有大厅逻辑服和房间逻辑服,我们会启动多个房间逻辑服及启动一个大厅逻辑服。

房间逻辑服会提供一个返回房间数量的方法,大厅逻辑服有一个 action,该 action 会同时向多个房间逻辑服请求数据, 目的是查看各房间逻辑服的房间数量信息。

定义数据协议

我们定义一个 RoomNumMsg 类,用来记录当前房间逻辑服的房间数量。

@ProtobufClass
public class RoomNumMsg {
public int roomCount;
}

房间逻辑服

  • DemoSameRoomLogicServer 房间逻辑服
  • DemoRoomAction

房间逻辑服的createBrokerClientBuilder 方法没有提供 BrokerClientBuilder 构建器。 在后面启动类中,我们会手动赋值一个自定义的构建器。

@ActionController(9)
public class DemoRoomAction {
@ActionMethod(0)
public RoomNumMsg countRoom() {
RoomNumMsg roomNumMsg = new RoomNumMsg();
roomNumMsg.roomCount = RandomKit.random(1, 100);
return roomNumMsg;
}
}

public class DemoSameRoomLogicServer extends AbstractBrokerClientStartup {

@Override
public BarSkeleton createBarSkeleton() {
var config = new BarSkeletonBuilderParamConfig()
.scanActionPackage(DemoRoomAction.class);

var builder = config.createBuilder();
builder.addInOut(new DebugInOut());
return builder.build();
}

@Override
public BrokerClientBuilder createBrokerClientBuilder() {
return null;
}
}

大厅逻辑服

@ActionController(8)
public class DemoHallAction {
@ActionMethod(0)
public void count(FlowContext flowContext) {
CmdInfo cmdInfo = CmdInfo.of(DemoCmdForRoom.cmd, DemoCmdForRoom.countRoom);

flowContext.invokeModuleCollectMessageAsync(cmdInfo, responseCollectMessage -> {
var messageList = responseCollectMessage.getMessageList();

for (ResponseCollectItemMessage itemMessage : messageList) {
RoomNumMsg roomNumMsg = itemMessage.getData(RoomNumMsg.class);
log.info("{} ", roomNumMsg);
}
});
}
}

public class DemoSameHallLogicServer extends AbstractBrokerClientStartup {

@Override
public BarSkeleton createBarSkeleton() {
var config = new BarSkeletonBuilderParamConfig()
.scanActionPackage(DemoHallAction.class);

var builder = config.createBuilder();
builder.addInOut(new DebugInOut());
return builder.build();
}

@Override
public BrokerClientBuilder createBrokerClientBuilder() {
BrokerClientBuilder builder = BrokerClient.newBuilder();
builder.appName("DemoSameHallLogicServer");
return builder;
}
}
  • code 7,request/multiple_response,请求同类型多个游戏逻辑服
  • code 10, 遍历每个房间逻辑服响应的数据

启动类

public class DemoInteractionSameApplication {
public static void main(String[] args) {

// cn: 创建 3 个房间逻辑服
// Create 3 DemoSameRoomLogicServer
DemoSameRoomLogicServer roomServer1 = createRoomServer(1);
DemoSameRoomLogicServer roomServer2 = createRoomServer(2);
DemoSameRoomLogicServer roomServer3 = createRoomServer(3);

// logicList. cn: 逻辑服列表
List<AbstractBrokerClientStartup> logicList = List.of(
// DemoSameHallLogicServer
new DemoSameHallLogicServer(),
// DemoSameRoomLogicServer: 1、2、3
roomServer1,
roomServer2,
roomServer3
);

// 游戏对外服端口
int port = 10100;
NettySimpleHelper.run(port, logicList);
}

private static DemoSameRoomLogicServer createRoomServer(int id) {
// BrokerClient 构建器,房间逻辑服的信息
BrokerClientBuilder brokerClientBuilder = BrokerClient.newBuilder()
// cn: 逻辑服的唯一 id
// gameLogicServer id
.id(String.valueOf(id))
// cn: 游戏逻辑服名字
// gameLogicServer name.
.appName("DemoSameRoomLogicServer-" + id)
// cn: 同类型标签
// gameLogicServer tag.
.tag("DemoSameRoomLogicServer");

// cn: 创建房间逻辑服
// Create DemoSameRoomLogicServer
DemoSameRoomLogicServer roomLogicServer = new DemoSameRoomLogicServer();
roomLogicServer.setBrokerClientBuilder(brokerClientBuilder);
return roomLogicServer;
}
}

我们启动了 4 个游戏逻辑服,分别是:1个大厅游戏逻辑服、3个房间游戏逻辑服。 其中房间游戏逻辑服的 BrokerClient 构建器是在 createRoomServer 方法中赋值的,构建器的作用是配置游戏逻辑服的当前信息。

  • code 36,最为关键,是用来确定【同类型】游戏逻辑服的。

控制台日志

从日志中我们可以看见,有【同类型】3台【房间逻辑服】连接到游戏网关了,tag 的值是我们设置的 roomLogic 。

22:30:14.045 [Bolt-default-executor-5-thread-8] [] INFO  CommonStdout.print(BrokerPrintKit.java:73) GameBrokerServer:10200 --- gameLogicServerList:
{Number of servers:3, tag:'DemoSameRoomLogicServer'}
{Number of servers:1, tag:'DemoSameHallLogicServer'}
{Number of servers:1, tag:'external'}

测试

see DemoInteractionSameClient

public class DemoInteractionSameClient {
public static void main(String[] args) {
ClientUserConfigs.closeLog();

List<InputCommandRegion> inputCommandRegions = List.of(
new InternalRegion()
);

new ClientRunOne()
.setInputCommandRegions(inputCommandRegions)
.startup();
}

static class InternalRegion extends AbstractInputCommandRegion {
@Override
public void initInputCommand() {
inputCommandCreate.cmd = DemoHallCmd.cmd;

ofCommand(DemoHallCmd.count).setTitle("count");

TaskKit.runOnce(() -> {
ofRequestCommand(DemoHallCmd.count).execute();
}, 10, TimeUnit.MILLISECONDS);
}
}
}

注意事项

注意

request/multiple_response 模型必须要有返回值,被调用端的 action 不能是 void。

如果只想触发同类型多个游戏逻辑服的 action,可以考虑使用 EventBus。

小结

可以看出,在 ioGame 中向【同类型】的游戏逻辑服发起请求是非常简单的事,只需要一个方法就能做到。

flowContext.invokeModuleCollectMessageAsync

框架对这块的处理使用了 CompletableFuture、ForkJoinPool 等技术,很好的利用了并行来访问所有相同的游戏逻辑服。 上面的示例中,假设每个房间逻辑服的 count 方法耗时为 0.5 秒,总的访问时间最高是 0.5 秒,而不是 1.5 秒。

最后,发挥你的想象力,把这一特性用起来!