### Java: Configure and Start Game External Server Source: https://iohao.github.io/game/docs/intro/quick_zero_demo This Java example illustrates how to set up and start the game external server. It configures the server to listen on port 10100, uses WebSocket for client connections, and specifies the address of the Broker (game gateway) for inter-server communication. This server acts as the entry point for client requests. ```Java public static void main(String[] args) { var builder = DefaultExternalServer .newBuilder(10100) .externalJoinEnum(ExternalJoinEnum.WEBSOCKET) .brokerAddress(new BrokerAddress("127.0.0.1", IoGameGlobalConfig.brokerPort)); builder.build().startup(); } ``` -------------------------------- ### Java: Configure and Start Game Gateway Server Source: https://iohao.github.io/game/docs/intro/quick_zero_demo This Java code demonstrates the minimal setup required to initialize and launch the game gateway server using `BrokerServerBuilder`. The gateway server typically listens on port 10200 by default, facilitating communication between external clients and game logic servers. ```Java public static void main(String[] args) { BrokerServerBuilder brokerServerBuilder = BrokerServer.newBuilder(); brokerServerBuilder.build().startup(); } ``` -------------------------------- ### Run ioGame Server from Packaged Jar Source: https://iohao.github.io/game/docs/intro/quick_zero_demo Command to execute the packaged JAR file, starting the ioGame server. The server usually starts within 0.x seconds. ```bash java -jar simple-one-1.0-SNAPSHOT-jar-with-dependencies.jar ``` -------------------------------- ### Clone ioGameSimpleOne Example Repository Source: https://iohao.github.io/game/docs/intro/quick_zero_demo Command to download the example source code for the ioGameSimpleOne project from GitHub. ```bash git clone https://github.com/iohao/ioGameSimpleOne.git ``` -------------------------------- ### ioGame Action Execution Console Log Example Source: https://iohao.github.io/game/docs/intro/intro Provides an example of the console output generated when an ioGame action business method is executed. This log details the method called, user ID, input parameters, response data, and execution time, aiding in debugging and monitoring. ```Console Output ┏━━━━━ Debug. [(DemoAction.java:5).here] ━━━━━ [cmd:1-0 65536] ━━━━━ [xxx逻辑服 - id:[76526c134cc88232379167be83e4ddfc] ┣ userId: 1 ┣ 参数: message : LoginVerifyMessage(jwt=hello) ┣ 响应: UserMessage(name=Michael Jackson, hello) ┣ 时间: 1 ms (业务方法总耗时) ┗━━━━━ [ioGameVersion] ━━━━━ [线程:User-8-2] ━━━━━━━ [traceId:956230991452569600] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` -------------------------------- ### Java Example: Starting Multiple Servers in a Single Process Source: https://iohao.github.io/game/docs/intro/manual/netty_run_one This Java code demonstrates how to simultaneously start an external game server, a game gateway, and a list of game logic servers within a single Java process using ioGame's `NettyRunOne` utility. The code sets up the `ExternalServer`, `BrokerServer`, and a list of `AbstractBrokerClientStartup` instances (like `WeatherLogicStartup`) before initiating the startup sequence. Specifically, lines 14-17 (conceptually, based on the provided description) correspond to setting the external server, broker server, logic server list, and finally calling the startup method. ```Java public class MyOneApplication { public static void main(String[] args) { ExternalServer externalServer = new MyExternalServer() .createExternalServer(ExternalGlobalConfig.externalPort); BrokerServer brokerServer = new MyBrokerServer() .createBrokerServer(); WeatherLogicStartup weatherLogicStartup = new WeatherLogicStartup(); List logicServerList = List.of(weatherLogicStartup); new NettyRunOne() .setExternalServer(externalServer) .setBrokerServer(brokerServer) .setLogicServerList(logicServerList) .startup(); } } ``` -------------------------------- ### Add ioGame Dependency to Maven pom.xml Source: https://iohao.github.io/game/docs/intro/quick_zero_demo Configuration for Maven's pom.xml to include the ioGame 'run-one-netty' dependency. Users should replace 'xx.xx' with the actual ioGame version. ```xml 21 xx.xx com.iohao.game run-one-netty ${ioGame.version} ``` -------------------------------- ### Package ioGame Project into Executable Jar Source: https://iohao.github.io/game/docs/intro/quick_zero_demo Maven command to clean and package the project into a self-contained JAR file, typically found in the 'target' directory. The resulting JAR is about 15MB. ```bash mvn clean package ``` -------------------------------- ### ioGame Console Log Field Reference Source: https://iohao.github.io/game/docs/intro/intro Detailed reference for the fields displayed in the ioGame console log output. Each entry describes a specific field, its purpose, and typical values, facilitating quick problem localization and understanding of business execution flow. ```APIDOC Debug. [(DemoAction.java:5).here]: Indicates the business method executed (DemoAction.here) and its line number (5). Clicking this in the tool navigates to the code. userId: The ID of the user who initiated the request. 参数 (Parameters): Typically the values passed from the game client. 响应 (Response): The value returned by the business method, pushed to the game client by the framework. 时间 (Time): Total time taken to execute the business method, useful for performance optimization. 路由信息 (Routing information): [cmd - subCmd] is the unique access address. ioGameVersion: The current ioGame version in use. 线程 (Thread): The thread used to execute the action. traceId: Full link call log tracking ID, unique for each request (very useful in distributed systems). 逻辑服 (Logic Server): The ID of the current game logic server. ``` -------------------------------- ### Implement ioGame Logic Server with AbstractBrokerClientStartup Source: https://iohao.github.io/game/docs/intro/quick_zero_demo Java class `DemoLogicServer` extending `AbstractBrokerClientStartup` to define the game logic server. It implements `createBarSkeleton` for business framework configuration, `createBrokerClientBuilder` for client information, and `createBrokerAddress` for gateway connection details. ```java public class DemoLogicServer extends AbstractBrokerClientStartup { @Override public BarSkeleton createBarSkeleton() { var config = new BarSkeletonBuilderParamConfig() .scanActionPackage(DemoAction.class); var builder = config.createBuilder(); builder.addInOut(new DebugInOut()); return builder.build(); } @Override public BrokerClientBuilder createBrokerClientBuilder() { BrokerClientBuilder builder = BrokerClient.newBuilder(); builder.appName("DemoLogicServer"); return builder; } @Override public BrokerAddress createBrokerAddress() { String localIp = "127.0.0.1"; int brokerPort = IoGameGlobalConfig.brokerPort; return new BrokerAddress(localIp, brokerPort); } } ``` -------------------------------- ### C# Client Example for Unity Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and Unity using C#, Protobuf, Netty, and WebSocket. ```C# https://github.com/iohao/ioGameSdkCsharpExampleUnity ``` -------------------------------- ### Server-side Code Examples for ioGame Source: https://iohao.github.io/game/docs/intro/examples/code_generate Reference to the ioGameExamples GitHub repository containing server-side code examples, specifically highlighting SdkApplication and GenerateTest paths. ```Java https://github.com/iohao/ioGameExamples path : SdkExample * SdkApplication * GenerateTest ``` -------------------------------- ### C# Client Example for Godot Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and Godot using C#, Protobuf, Netty, and WebSocket. ```C# https://github.com/iohao/ioGameSdkCsharpExampleGodot ``` -------------------------------- ### Java ioGame Action Controller Implementation Source: https://iohao.github.io/game/docs/intro/intro Illustrates a game server action controller (DemoAction) that processes incoming business data. The @ActionController and @ActionMethod annotations define the action, which can handle TCP, WebSocket, and UDP communications. The 'here' method receives LoginVerifyMessage and returns UserMessage, demonstrating a simple business logic flow. ```Java @Slf4j @ActionController(1) public class DemoAction { @ActionMethod(0) public UserMessage here(LoginVerifyMessage message) { var userMessage = new UserMessage(); userMessage.name = "Michael Jackson, " + message.jwt; return userMessage; } } ``` -------------------------------- ### TypeScript Client Example for Vue Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and Vue using TypeScript, Protobuf, Netty, and WebSocket. ```TypeScript https://github.com/vuejs/ ``` -------------------------------- ### Java jprotobuf Data Protocol Definition Source: https://iohao.github.io/game/docs/intro/intro Defines two data protocols, LoginVerifyMessage and UserMessage, using jprotobuf for client-server data exchange. jprotobuf simplifies Google Protobuf usage while maintaining equivalent performance, serving as DTOs or POJOs for business data transmission. ```Java @ProtobufClass public class LoginVerifyMessage { public String jwt; } @ProtobufClass public class UserMessage { public String name; } ``` -------------------------------- ### Define HelloMessage Business Data Protocol with Jprotobuf Source: https://iohao.github.io/game/docs/intro/quick_zero_demo Example Java class `HelloMessage` annotated with `@ProtobufClass` to define a business data protocol using Jprotobuf. This class serves as a DTO/POJO for data transmission in game server development. ```java @ProtobufClass public class HelloMessage { public String name; @Override public String toString() { return "HelloMessage{name='"+ name + "'}"; } } ``` -------------------------------- ### GDScript Client Example for Godot Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and Godot using GDScript, Protobuf, Netty, and WebSocket. ```GDScript https://github.com/iohao/ioGameSdkGDScriptExampleGodot ``` -------------------------------- ### TypeScript Client Example for HTML/Webpack Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and a webpack-based HTML/TypeScript project using Protobuf, Netty, and WebSocket. ```TypeScript https://github.com/webpack/webpack ``` -------------------------------- ### TypeScript Client Example for Angular Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and Angular using TypeScript, Protobuf, Netty, and WebSocket. ```TypeScript https://github.com/angular/angular ``` -------------------------------- ### TypeScript Client Example for Cocos Creator Source: https://iohao.github.io/game/docs/intro/examples/code_generate An example demonstrating communication between ioGame and Cocos Creator using TypeScript, Protobuf, Netty, and WebSocket. ```TypeScript https://github.com/iohao/ioGameSdkTsExampleCocos ``` -------------------------------- ### Implementing Runner for Domain Event Configuration Source: https://iohao.github.io/game/docs/intro/core/runner This example demonstrates how to implement the `Runner` interface to manage domain event related configurations. It shows how to add event handlers for user bag and email events and how to register the `MyDomainRunner` with the `BarSkeleton` in the `DemoLogicServer`. ```Java public class MyDomainRunner implements Runner { @Override public void onStart(BarSkeleton skeleton) { DomainEventContextParam contextParam = new DomainEventContextParam(); contextParam.addEventHandler(new UserBagEventHandler()); contextParam.addEventHandler(new UserEmailEventHandler()); DomainEventContext domainEventContext = new DomainEventContext(contextParam); domainEventContext.startup(); } } public class DemoLogicServer extends AbstractBrokerClientStartup { ... @Override public BarSkeleton createBarSkeleton() { ... BarSkeletonBuilder builder = config.createBuilder(); builder.addRunner(new MyDomainRunner()); return builder.build(); } } public record UserLoginEo(long id) implements Eo { } public class UserBagEventHandler implements DomainEventHandler { @Override public void onEvent(UserLoginEo event, boolean endOfBatch) { log.info("UserBag : {}", event); } } public class UserEmailEventHandler implements DomainEventHandler { @Override public void onEvent(UserLoginEo event, boolean endOfBatch) { log.info("UserEmail : {}", event); } } ``` -------------------------------- ### C# ioGame SDK Network and WebSocket Configuration Source: https://iohao.github.io/game/docs/intro/examples/example_sdk_unity This C# code defines the MyNetConfig class, which is central to initializing the ioGame SDK. It configures network settings, enables development mode, sets the language, and assigns custom callbacks for message listening and console logging. The SocketInit method establishes a WebSocket connection to the game server, handles user login verification, and implements a periodic heartbeat mechanism. The IoGameUnityWebSocket class extends SimpleNetChannel to manage the WebSocket lifecycle, including connection, message reception, and sending data. ```C# namespace Config { public abstract class MyNetConfig { private static IoGameUnityWebSocket _socket; public static long CurrentTimeMillis { get; set; } public static void StartNet() { // biz code init GameCode.Init(); Index.Listen(); // --------- IoGameSetting --------- IoGameSetting.EnableDevMode = true; // China or Us IoGameSetting.SetLanguage(IoGameLanguage.China); // message callback. 回调监听 IoGameSetting.ListenMessageCallback = new MyListenMessageCallback(); IoGameSetting.GameGameConsole = new MyGameConsole(); // socket SocketInit(); IoGameSetting.StartNet(); } private static void SocketInit() { IoGameSetting.Url = "ws://127.0.0.1:10100/websocket"; // socket _socket = new IoGameUnityWebSocket(); IoGameSetting.NetChannel = _socket; _socket.OnOpen += (_, _) => { Debug.Log("WebSocket OnOpen new!"); // login var loginVerifyMessage = new LoginVerifyMessage { Jwt = "1234567" }; SdkAction.OfLoginVerify(loginVerifyMessage, result => { var userMessage = result.GetValue(); result.Log($"userMessage: {userMessage}"); }); // heartbeat IdleTimer(); }; } private static async void IdleTimer() { var heartbeatMessage = new ExternalMessage().ToByteArray(); var counter = 0; while (true) { await Task.Delay(8000); Debug.Log($"-------- unity new ...HeartbeatMessage {counter++}"); // Send heartbeat to server. 发送心跳给服务器 IoGameSetting.NetChannel.WriteAndFlush(heartbeatMessage); } } } internal class MyListenMessageCallback : SimpleListenMessageCallback { public override void OnIdleCallback(ExternalMessage message) { var dataBytes = message.Data.ToByteArray(); var longValue = new LongValue(); longValue.MergeFrom(new CodedInputStream(dataBytes)); /* * Synchronize the time of each heartbeat with that of the server. * 每次心跳与服务器的时间同步 */ MyNetConfig.CurrentTimeMillis = longValue.Value; } } internal class MyGameConsole : IGameConsole { public void Log(object value) { Debug.Log(value); } } public sealed class IoGameUnityWebSocket : SimpleNetChannel { public string Url { set; get; } WebSocket _socket; public event EventHandler OnOpen = (_, _) => { Debug.Log("WebSocket OnOpen"); }; public override void Prepare() { Url ??= IoGameSetting.Url; _socket = new WebSocket(Url); // 注册回调 _socket.OnOpen += OnOpen; _socket.OnClose += (_, e) => { Debug.Log($"Connection closed! {e}"); }; _socket.OnError += (_, e) => { Debug.LogError($"e {e}"); }; _socket.OnMessage += (m, e) => { var packet = e.RawData; AcceptMessage(ExternalMessage.Parser.ParseFrom(packet)); }; // 连接 _socket.ConnectAsync(); } public override void WriteAndFlush(byte[] bytes) { _socket.SendAsync(bytes); } } } ``` -------------------------------- ### C# ioGame SDK Network and Core Configuration Source: https://iohao.github.io/game/docs/intro/examples/example_sdk_godot_charp This C# code defines the `MyNetConfig` class, which is central to configuring the ioGame SDK. It initializes core SDK settings, sets up network communication via WebSockets (including connection, login, and heartbeat mechanisms), and integrates custom message listeners and console logging for Godot. It also includes implementations for `MyListenMessageCallback` to synchronize server time and `MyGameConsole` for logging. ```C# namespace My.Game { public abstract class MyNetConfig { private static IoGameGodotWebSocket _socket; public static long CurrentTimeMillis { get; set; } public static void StartNet() { // biz code init GameCode.Init(); Index.Listen(); // --------- IoGameSetting --------- IoGameSetting.EnableDevMode = true; // China or Us IoGameSetting.SetLanguage(IoGameLanguage.China); // message callback. 回调监听 IoGameSetting.ListenMessageCallback = new MyListenMessageCallback(); IoGameSetting.GameGameConsole = new MyGameConsole(); // socket SocketInit(); IoGameSetting.StartNet(); } public static void Poll() { // Receiving server messages _socket.Poll(); } private static void SocketInit() { IoGameSetting.Url = "ws://127.0.0.1:10100/websocket"; _socket = new IoGameGodotWebSocket(); IoGameSetting.NetChannel = _socket; // login _socket.OnOpen += () => { var loginVerifyMessage = new LoginVerifyMessage { Jwt = "10" }; SdkAction.OfLoginVerify(loginVerifyMessage, result => { var userMessage = result.GetValue(); result.Log($"userMessage {userMessage}"); }); // heartbeat IdleTimer(); }; _socket.OnConnecting += () => { GD.Print("My OnConnecting"); }; _socket.OnConnectError += error => { GD.PrintErr($"My OnConnectError --- {error}"); }; _socket.OnClosing += () => { GD.Print("My OnClosing"); }; _socket.OnClosed += () => { GD.Print("My OnClosed"); }; } private static async void IdleTimer() { var heartbeatMessage = new ExternalMessage().ToByteArray(); var counter = 0; while (true) { await Task.Delay(8000); GD.Print($"-------- ..HeartbeatMessage {counter++}"); // Send heartbeat to server. 发送心跳给服务器 IoGameSetting.NetChannel.WriteAndFlush(heartbeatMessage); } } } internal class MyListenMessageCallback : SimpleListenMessageCallback { public override void OnIdleCallback(ExternalMessage message) { var dataBytes = message.Data.ToByteArray(); var longValue = new LongValue(); longValue.MergeFrom(new CodedInputStream(dataBytes)); /* * Synchronize the time of each heartbeat with that of the server. * 每次心跳与服务器的时间同步 */ MyNetConfig.CurrentTimeMillis = longValue.Value; } } internal class MyGameConsole : IGameConsole { public void Log(object value) { GD.Print(value); } } } ``` -------------------------------- ### DebugInOut Plugin Console Log Preview Source: https://iohao.github.io/game/docs/intro/core_plugin/action_debug This snippet displays an example of the detailed log output generated by the DebugInOut plugin. It includes user ID, request parameters, response data, execution time, and routing information, aiding in quick debugging and understanding request flow. ```Text ┏━━━━━ Debug. [(DemoAction.java:5).here] ━━━━━ [cmd:1-0 65536] ━━━━━ [xxx逻辑服 - id:[76526c134cc88232379167be83e4ddfc] ┣ userId: 1 ┣ 参数: message : LoginVerifyMessage(jwt=hello) ┣ 响应: UserMessage(name=Michael Jackson, hello) ┣ 时间: 1 ms (业务方法总耗时) ┗━━━━━ [ioGameVersion] ━━━━━ [线程:User-8-2] ━━━━━━━ [traceId:956230991452569600] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` -------------------------------- ### Java Example for ioGame SDK Code Generation Source: https://iohao.github.io/game/docs/intro/examples/code_generate This Java `main` method demonstrates the core steps to configure and execute the code generation process within the ioGame framework. It covers loading game logic, setting access authentication, and invoking specific generators for TypeScript, C#, GDScript, error codes, and .proto files. ```Java public final class GenerateTest { ... public static void main(String[] args) { // CHINA or US Locale.setDefault(Locale.CHINA); // Load the business framework of each gameLogicServer // 加载业务逻辑服 SdkApplication.listLogic().forEach(BrokerClientStartup::createBarSkeleton); /* * GameExternalServer accessAuthentication * 游戏对外服访问权限,不生成权限控制的 action */ SdkApplication.extractedAccess(); DocumentAccessAuthentication reject = ExternalGlobalConfig.accessAuthenticationHook::reject; IoGameDocumentHelper.setDocumentAccessAuthentication(reject); /* * Generate actions, broadcasts, and error codes. * cn: 生成 action、广播、错误码 */ // ----- About generating TypeScript code ----- // generateCodeVue(); // generateCocosCreator(); // ----- About generating C# code ----- // generateCodeCsharpGodot(); // generateCodeCsharpUnity(); // ----- About generating GDScript code ----- generateCodeGDScriptGodot(); // Added an enumeration error code class to generate error code related information IoGameDocumentHelper.addErrorCodeClass(SdkGameCodeEnum.class); // Generate document; IoGameDocumentHelper.generateDocument(); // Generate .proto generateProtoFile(); } static void generateProtoFile() { // By default, it will be generated in the target/proto directory // .proto 默认生成的目录为 target/proto // The package name to be scanned String packagePath = "com.iohao.example.sdk.data"; GenerateFileKit.generate(packagePath); } } ``` -------------------------------- ### Centralizing External Access Authentication Configuration with Runner Source: https://iohao.github.io/game/docs/intro/core/runner This example illustrates using the `Runner` interface to centralize external access authentication configurations. It shows how to set identity verification, add ignored authentication commands, and add rejection commands, then register this Runner with the `ExternalBrokerClientStartup`. ```Java public class MyExternalAccessAuthenticationRunner implements Runner { @Override public void onStart(BarSkeleton skeleton) { var accessAuthenticationHook = ExternalGlobalConfig.accessAuthenticationHook; accessAuthenticationHook.setVerifyIdentity(true); accessAuthenticationHook.addIgnoreAuthenticationCmd(1, 1); accessAuthenticationHook.addIgnoreAuthenticationCmd(2); accessAuthenticationHook.addRejectionCmd(10); accessAuthenticationHook.addRejectionCmd(11, 1); } } public class MyExternalServer extends ExternalBrokerClientStartup { @Override public BarSkeleton createBarSkeleton() { BarSkeletonBuilder builder = ...; builder.addRunner(new MyExternalAccessAuthenticationRunner()); return builder.build(); } } ``` -------------------------------- ### APIDOC: ClientUsers Utility for Task Coordination Source: https://iohao.github.io/game/docs/intro/extension_module/simulation_client This section describes the `ClientUsers` utility class, specifically its `execute(Runnable task)` method. This method allows tasks to be queued and executed only after all simulated players have successfully logged in, which is useful for scenarios requiring synchronized test starts. ```APIDOC ClientUsers: execute(task: Runnable): void task: The Runnable task to be executed. Description: Adds a task to a queue that will only start executing after all simulated players have successfully logged in. ``` -------------------------------- ### Java: OnceTaskListener Example for Game Round Management Source: https://iohao.github.io/game/docs/intro/kit/task_kit Illustrates using TaskKit.runOnce with OnceTaskListener to manage game rounds and countdowns. The triggerUpdate method controls task execution based on the current round, eliminating explicit timer cancellation. ```Java public void test() { Room room = new Room(); // Start next round room.startNextRound(); // Start next round, previous task will not execute room.startNextRound(); } record OperationTask(int currentRound, Room room) implements OnceTaskListener { @Override public void onUpdate() { room.notice(); } @Override public boolean triggerUpdate() { return currentRound == room.round.get(); } } class Room { AtomicInteger round = new AtomicInteger(1); long currentOperationPlayerId; void notice() { this.startNextRound(); } void startNextRound() { int currentRound = this.round.incrementAndGet(); this.currentOperationPlayerId = 100; TaskKit.runOnce(new OperationTask(currentRound, this), 1, TimeUnit.SECONDS); } } ``` -------------------------------- ### Java Action Method Example for ExternalMessage Response Source: https://iohao.github.io/game/docs/intro/manual_high/external_message Illustrates how an action method in Java processes a message and returns a new object, which is then assigned to ExternalMessage.data by the game's external service. ```Java @ActionController(1) public class DemoAction { @ActionMethod(0) public HelloMessage here(HelloMessage message) { HelloMessage newHelloMessage = ... return newHelloMessage; } } ``` -------------------------------- ### Example Console Output for Broadcast Logs Source: https://iohao.github.io/game/docs/intro/communication/broadcast These console logs demonstrate the format and content of broadcast messages when logging is enabled. They display key details such as the user ID (including '全服广播' for all-server broadcasts), the broadcast data, and the timestamp of the broadcast event. ```Console ┏━━━━━ 广播. [(DemoBroadcastApplication.java:40)] ━━━ [cmd:7 - subCmd:0 - cmdMerge:458752] ┣ userId: 全服广播 ┣ 广播数据: DemoBroadcastMessage(msg=broadcast hello ,253) ┣ 广播时间: 2022-05-19 21:31:47.728 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┏━━━━━ 广播. [(DemoBroadcastApplication.java:40)] ━━━ [cmd:7 - subCmd:0 - cmdMerge:458752] ┣ userId: 1 ┣ 广播数据: DemoBroadcastMessage(msg=broadcast hello ,1) ┣ 广播时间: 2022-05-19 21:32:42.732 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┏━━━━━ 广播. [(TankAction.java:116)] ━━━ [cmd:2 - subCmd:7 - cmdMerge:131079] ┣ userId: [1,5,7] ┣ 广播数据: BarHelloPb(amount=7) ┣ 广播时间: 2022-07-14 18:31:02.253 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` -------------------------------- ### Define Action Controller and Method in DemoAction (Java) Source: https://iohao.github.io/game/docs/intro/overall/request_processing_procedure This Java example illustrates the definition of an action controller and method using `@ActionController` and `@ActionMethod` annotations. The `DemoAction` class with ID 1 contains a method `here` with ID 0 that processes a `HelloMessage` and returns a `HelloMessage`, representing the core business logic execution point. ```Java @ActionController(1) public class DemoAction { @ActionMethod(0) public HelloMessage here(HelloMessage message) { return ...; } } ``` -------------------------------- ### Java Code for GDScript Code Generation in ioGame Source: https://iohao.github.io/game/docs/intro/version_log This Java class `GenerateTest` demonstrates how to programmatically generate GDScript code for the ioGame SDK. It utilizes `IoGameDocumentHelper` and `GDScriptDocumentGenerate` to create actions, broadcasts, and error codes, with an example of setting the output path for Godot projects. It also shows how to load business frameworks and add error code classes. ```Java public final class GenerateTest { // setting root path static String rootPath = "/Users/join/gitme/ioGame-sdk/"; public static void main(String[] args) { // CHINA or US Locale.setDefault(Locale.CHINA); // Load the business framework of each gameLogicServer // cn: 加载游戏逻辑服的业务框架 yourListLogic().forEach(BrokerClientStartup::createBarSkeleton); /* * Generate actions, broadcasts, and error codes. * cn: 生成 action、广播、错误码 */ // ----- About generating GDScript code ----- generateCodeGDScriptGodot(); // Added an enumeration error code class to generate error code related information IoGameDocumentHelper.addErrorCodeClass(YourGameCodeEnum.class); // Generate document IoGameDocumentHelper.generateDocument(); } private static void generateCodeGDScriptGodot() { var documentGenerate = new GDScriptDocumentGenerate(); // By default, it will be generated in the target/code directory // cn: 设置代码生成所存放的路径,如果不做任何设置,将会生成在 target/code 目录中 String path = rootPath + "ioGameSdkGDScriptExampleGodot/gen/code"; documentGenerate.setPath(path); IoGameDocumentHelper.addDocumentGenerate(documentGenerate); } } ``` -------------------------------- ### Java Example: Enabling JSR380 Validation in ioGame Framework Source: https://iohao.github.io/game/docs/intro/core/jsr380 This snippet demonstrates how to enable the JSR380 validation feature within the ioGame business framework. By setting 'builder.getSetting().setValidator(true)', the framework will automatically apply validation rules defined by JSR380 annotations. ```java public BarSkeleton createBarSkeleton() { BarSkeletonBuilder builder = ...; builder.getSetting().setValidator(true); return builder.build(); } ``` -------------------------------- ### Getting EventBus Instances in ioGame Source: https://iohao.github.io/game/docs/intro/communication/event_bus Demonstrates three primary methods to obtain an EventBus instance: directly from FlowContext, by using BrokerClientContext's ID with EventBusRegion, or through a BarSkeleton's options. These methods provide access to the event bus for publishing and subscribing to events. ```Java // example-1 EventBus eventBus = flowContext.getEventBus(); // example-2 BrokerClientContext brokerClientContext = flowContext.getBrokerClientContext(); String id = brokerClientContext.getId(); EventBus eventBus = EventBusRegion.getEventBus(id); // example-3 BarSkeleton barSkeleton = ... EventBus eventBus = barSkeleton.option(SkeletonAttr.eventBus); ``` -------------------------------- ### Configuring Different CmdCacheOption for Specific Routes Source: https://iohao.github.io/game/docs/intro/external/cache This example illustrates how to apply different CmdCacheOption configurations to various routes. It first sets a default cache option for the DefaultExternalCmdCache, which applies to route 22-1. Subsequently, it creates a custom CmdCacheOption with a shorter expiration (30 seconds) and check interval (5 seconds), applying this custom option to routes 22-2 and 22-3, overriding the default. ```Java ... void extractedExternalCache() { DefaultExternalCmdCache externalCmdCache = new DefaultExternalCmdCache(); ExternalGlobalConfig.externalCmdCache = externalCmdCache; CmdCacheOption defaultOption = createCmdCacheOption(); externalCmdCache.setCmdCacheOption(defaultOption); externalCmdCache.addCmd(22, 1); CmdCacheOption optionCustom = CmdCacheOption.newBuilder() .setExpireTime(Duration.ofSeconds(30)) .setExpireCheckTime(Duration.ofSeconds(5)) .build(); externalCmdCache.addCmd(22, 2, optionCustom); externalCmdCache.addCmd(22, 3, optionCustom); } ``` -------------------------------- ### Exclude Specific Routes from DebugInOut Logging in Java Source: https://iohao.github.io/game/docs/intro/core_plugin/action_debug This Java example shows how to customize the DebugInOut plugin to ignore logging for specific routes using a hardcoded condition. It demonstrates setting a custom print consumer to filter logs based on command and subcommand information, preventing unnecessary output for certain actions. ```Java ... @Override public BarSkeleton createBarSkeleton() { BarSkeletonBuilder builder = ...; DebugInOut debugInOut = new DebugInOut(); builder.addInOut(debugInOut); debugInOut.setPrintConsumer((message, flowContext) -> { CmdInfo cmdInfo = flowContext.getCmdInfo(); if (cmdInfo.getCmd() == 1 && cmdInfo.getSubCmd() == 3) { return; } System.out.println(message); }); ... } ``` -------------------------------- ### Java Startup Class for Multiple Game Logic Servers Source: https://iohao.github.io/game/docs/intro/communication/request_multiple_response This Java class demonstrates the main entry point for an ioGame application, setting up and running multiple game logic servers. It initializes one hall server and three room servers, configuring each room server with a unique ID and a shared tag 'DemoSameRoomLogicServer' using `BrokerClientBuilder` for type identification. ```Java 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 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; } } ``` -------------------------------- ### Java: Initial Game Logic Server Configuration Source: https://iohao.github.io/game/docs/intro/examples/code_generate This snippet shows the initial configuration of the SdkApplication to list the game logic servers. It demonstrates how ioGame loads a single SdkLogicServer for processing, which is a foundational step for the code generation process. ```Java public final class SdkApplication { static List listLogic() { return List.of( new SdkLogicServer() ); } } ``` -------------------------------- ### Java Example: JSR380 Validation with Annotations Source: https://iohao.github.io/game/docs/intro/core/jsr380 This example shows the clean business logic when using JSR380 annotations. By applying '@NotNull', '@Email', and '@Min' to the 'ValidMessage' fields, the framework handles all validation automatically, including error responses. This achieves the same validation effect as the manual example but with significantly less code in the action method. ```java @ActionController(1) public class JsrJakartaAction { @ActionMethod(1) public void verify(ValidMessage message) { // Your biz code // ... } } @ProtobufClass public class ValidMessage { @NotNull @Email public String email; @Min(value = 2, message = "Age error") public int age; } ``` -------------------------------- ### Java Example: Manual Validation without JSR380 Source: https://iohao.github.io/game/docs/intro/core/jsr380 This example demonstrates how to manually validate email format and age range without using JSR380. It shows the verbose code required for just two fields, highlighting how 'if-else' statements and regular expressions can clutter business logic. This approach becomes unmanageable with more validation rules or fields. ```java @ActionController(1) public class JsrJakartaAction { @ActionMethod(1) public void verify(ValidMessage message) { String email = message.email; GameCode.emailChecked.assertNullThrows(email == null); Pattern pattern = Pattern.compile("[a-zA-Z0-9_-]+@\\w+\\.[a-z]+(\\.[a-z]+)?"); var result = pattern.matcher(email).find(); GameCode.emailChecked.assertTrue(result); int age = message.age; GameCode.ageChecked.assertTrueThrows(age < 2); // Your biz code // ... } } @ProtobufClass public class ValidMessage { public String email; public int age; } @Getter public enum GameCode implements MsgExceptionInfo { emailChecked(100, "Email error."), ageChecked(101, "Age error."), ; final int code; final String msg; GameCode(int code, String msg) { this.code = code; this.msg = msg; } } ``` -------------------------------- ### Implement Room Game Logic Server and Action Source: https://iohao.github.io/game/docs/intro/communication/request_multiple_response This snippet defines `DemoRoomAction` with an `@ActionMethod` to return a random room count encapsulated in `RoomNumMsg`. It also shows `DemoSameRoomLogicServer`, which sets up the `BarSkeleton` for the action controller. The `createBrokerClientBuilder` method is intentionally left null, as the builder will be manually assigned during startup. ```Java @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; } } ``` -------------------------------- ### Configuring Custom Subscribe Selector Strategy for EventBus Source: https://iohao.github.io/game/docs/intro/communication/event_bus Provides an example of how developers can set a custom SubscribeSelectorStrategy for the EventBus during its initialization. This allows for advanced customization of how subscriber threads are selected, enabling tailored solutions beyond the built-in strategies. ```Java builder.addRunner(new EventBusRunner() { @Override public void registerEventBus(EventBus eventBus, BarSkeleton skeleton) { eventBus.setSubscribeSelectorStrategy(new YourSubscribeSelectorStrategy()); } }); ``` -------------------------------- ### UserVirtualExecutor Strategy Example for Event Subscribers Source: https://iohao.github.io/game/docs/intro/communication/event_bus Illustrates how to specify the userVirtualExecutor strategy for an event subscriber. This strategy utilizes virtual threads and is recommended for handling time-consuming operations such as database interactions or I/O, allowing for non-blocking execution and improved scalability. ```Java @EventBusSubscriber public class EmailEventBusSubscriber { @EventSubscribe(ExecutorSelector.userVirtualExecutor) public void mail(UserLoginEventMessage message) { // your biz code } } ``` -------------------------------- ### Java: Simulate Game Client Load Testing with PressureClient Source: https://iohao.github.io/game/docs/intro/extension_module/simulation_client This snippet demonstrates how to set up a load test client using `PressureClient`. It initializes a specified number of simulated users, each logging in and then repeatedly executing a specific action (`inc`) after a delay, simulating continuous player activity. Key aspects include setting the number of simulated players, managing user objects, and triggering login requests after a delay. ```Java public class PressureClient { public static void main(String[] args) throws InterruptedException { ClientUserConfigs.closeScanner = true; ClientUserConfigs.closeLog(); int userSize = 80; for (int i = 1; i <= userSize; i++) { long userId = i; TaskKit.execute(() -> start(userId)); } TimeUnit.SECONDS.sleep(1); } static void start(long userId) { ClientUser clientUser = new DefaultClientUser(); String jwt = String.valueOf(userId); clientUser.setJwt(jwt); TaskKit.runOnceSecond(() -> { CmdInfo cmdInfo = LoginCmd.of(LoginCmd.login); clientUser.getClientUserInputCommands() .ofRequestCommand(cmdInfo) .requestCommand.execute(); }); List inputCommandRegions = List.of( new LoginInputCommandRegion() , new PressureInputCommandRegion() ); new ClientRunOne() .setClientUser(clientUser) .setInputCommandRegions(inputCommandRegions) .startup(); } } ``` -------------------------------- ### Console Log Output for Game Broker Server Connections Source: https://iohao.github.io/game/docs/intro/communication/request_multiple_response This log snippet shows the console output from the game broker server, confirming that three 'DemoSameRoomLogicServer' instances and one 'DemoSameHallLogicServer' instance have successfully connected, identified by their respective tags. ```text 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'} ``` -------------------------------- ### Java: ioGame Code Generation Workflow Source: https://iohao.github.io/game/docs/intro/examples/code_generate This Java main method demonstrates the core process of ioGame code generation. It initializes the system locale, loads game logic servers, sets up route access control, and then triggers the generation of various artifacts including actions, broadcasts, error codes, C# Godot specific code, and .proto files. It also includes helper methods for configuring C# code output paths and generating .proto files. ```Java public final class GenerateTest { public static void main(String[] args) { // CHINA or US Locale.setDefault(Locale.CHINA); // Load the business framework of each gameLogicServer // c: 加载业务逻辑服 SdkApplication.listLogic().forEach(BrokerClientStartup::createBarSkeleton); // Set route access control. // cn: 设置路由访问权限控制 SdkApplication.extractedAccess(); DocumentAccessAuthentication reject = ExternalGlobalConfig.accessAuthenticationHook::reject; IoGameDocumentHelper.setDocumentAccessAuthentication(reject); /* * Generate actions, broadcasts, and error codes. * cn: 生成 action、广播、错误码 */ // ----- About generating C# code ----- generateCodeCsharpGodot(); // Added an enumeration error code class to generate error code related information // cn: 错误码的生成 IoGameDocumentHelper.addErrorCodeClass(SdkGameCodeEnum.class); // Generate document; IoGameDocumentHelper.generateDocument(); // Generate .proto // cn: 生成 .proto 文件 generateProtoFile(); } private static void generateCodeCsharpGodot() { var documentGenerate = new CsharpDocumentGenerate(); // 设置代码生成所存放的路径,如果不做任何设置,将会生成在 target/code 目录中 // By default, it will be generated in the target/code directory String path = rootPath + "ioGameSdkCsharpExampleGodot/script/gen/code"; documentGenerate.setPath(path); IoGameDocumentHelper.addDocumentGenerate(documentGenerate); } static void generateProtoFile() { // By default, it will be generated in the target/proto directory // .proto 默认生成的目录为 target/proto // The package name to be scanned String packagePath = "com.iohao.example.sdk.data"; GenerateFileKit.generate(packagePath); } } ``` -------------------------------- ### ioGame Spring Boot Application Startup Configuration Source: https://iohao.github.io/game/docs/intro/manual/integration_spring This Java code demonstrates the main application class for an ioGame project integrated with Spring Boot. It shows how to initialize the Spring application and, critically, how to register the ActionFactoryBeanForSpring as a Spring @Bean to enable Spring's management of ioGame action classes. ```Java @SpringBootApplication public class DemoSpringApplication { public static void main(String[] args) { SpringApplication.run(DemoSpringApplication.class, args); int port = ExternalGlobalConfig.externalPort; var demoLogicServer = new DemoSpringLogicServer(); NettySimpleHelper.run(port, List.of(demoLogicServer)); } @Bean public ActionFactoryBeanForSpring actionFactoryBean() { return ActionFactoryBeanForSpring.me(); } } ``` -------------------------------- ### APIDOC: OnceTaskListener Parameters Source: https://iohao.github.io/game/docs/intro/kit/task_kit Parameters for the OnceTaskListener interface and its usage with TaskKit.runOnce. ```APIDOC OnceTaskListener Parameters: taskListener: Type: OnceTaskListener Description: Listener delay: Type: long Description: Delay time unit: Type: TimeUnit Description: Time unit ``` -------------------------------- ### UserExecutor Strategy Example for Event Subscribers Source: https://iohao.github.io/game/docs/intro/communication/event_bus Demonstrates the use of the default userExecutor strategy for an event subscriber. This strategy is thread-safe and ensures that user-related events are processed on the same thread as the user's actions, effectively preventing concurrency issues for user-specific business logic. ```Java @EventBusSubscriber public class UserEventBusSubscriber { @EventSubscribe public void userLogin(UserLoginEventMessage message) { // your biz code } } ```