### Parallel Proto File Generation Setup Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Configures the generation of `.proto` files, specifying the output directory and a list of proto packages to be scanned. This setup supports parallel processing for faster generation. ```java private static void generateProtoFile() { String generateFolder = "/Users/join/gitme/game/MyGames/proto"; List protoPackageList = List.of("com.iohao.happy.robot" ,"com.iohao.happy.email"); var protoGenerateFile = new ProtoGenerateFile() // Generate the directory where the .proto file is stored .setGenerateFolder(generateFolder) // The package name to be scanned ``` -------------------------------- ### Action Parser Listener Example Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Implement ActionParserListener to observe action building or perform additional extensions. This example shows simple logging of the action command. ```java public final class YourActionParserListener implements ActionParserListener { @Override public void onActionCommand(ActionParserContext context) { ActionCommand actionCommand = context.getActionCommand(); log.info(actionCommand); } } void test() { BarSkeletonBuilder builder = ...; builder.addActionParserListener(new YourActionParserListener()); } ``` -------------------------------- ### Custom Document Generation Example Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Illustrates how to use a custom document generator by implementing the DocumentGenerate interface and adding it to IoGameDocumentHelper. ```java // 使用示例 private static void test() { var documentGenerate = new YourDocumentGenerate(); IoGameDocumentHelper.addDocumentGenerate(documentGenerate); } ``` -------------------------------- ### Quick Development Startup with NettyRunOne Source: https://context7.com/iohao/iogame/llms.txt NettyRunOne simplifies development by starting the external server, broker gateway, and logic servers in a single process. Ensure all necessary logic server implementations are provided. ```java import com.iohao.game.bolt.broker.client.AbstractBrokerClientStartup; import com.iohao.game.external.core.ExternalServer; import com.iohao.game.external.core.netty.DefaultExternalServer; import com.iohao.game.external.core.netty.simple.NettyRunOne; import java.util.List; public class GameApplication { public static void main(String[] args) { // Create logic servers List logicServers = List.of( new GameLogicServer(), new RoomLogicServer(), new ChatLogicServer() ); // Create external server (WebSocket on port 10100) ExternalServer externalServer = DefaultExternalServer .newBuilder(10100) .build(); // Start everything in one process new NettyRunOne() .setExternalServer(externalServer) .setLogicServerList(logicServers) .startup(); // Console output shows all routes and startup info: // ┏━━━━━ Debug. [(GameAction.java:15).play] ━━━━━ [cmd:2-1] ━━━━━ // ┣ userId: 10001 // ┣ Params: gameData : GameData(roomId=1) // ┣ Response: GameResult(score=100) // ┣ Time: 2 ms // ┗━━━━━ [ioGame 21.34] ━━━━━ [Thread:User-8-2] ━━━━━ [traceId:xxx] } } ``` -------------------------------- ### Home Game Server Actions Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Example actions provided by the 'Home' game logic server, including methods to return a string, a list of strings, and a list of Student objects. ```java // home 游戏逻辑服提供的 action public class HomeAction { @ActionMethod(HomeCmd.name) public String name() { return "a"; } @ActionMethod(HomeCmd.listName) public List listName() { return List.of("a", "b"); } @ActionMethod(HomeCmd.listStudent) public List listStudent() { Student student = new Student(); student.name = "a"; Student student2 = new Student(); student2.name = "b"; return List.of(student, student2); } } ``` -------------------------------- ### Method Code List Example Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action.txt Placeholder for method code definitions within the ioGame framework. Specific implementation details would be provided here. ```GDScript ${o} ``` -------------------------------- ### Simple Action Command Call Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_void_no_param.txt A basic example demonstrating how to call a simple action command. This is often used as a placeholder or for straightforward operations. ```gdscript ${actionSimpleName}.of_${actionMethodName}() ``` -------------------------------- ### Example Broadcast Listener Callback Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/broadcast_action.txt An example of a callback function for a broadcast listener. It processes the received data and logs information to the game console. ```GDScript Listener.listen_${o.methodName}(func(result: IoGame.ResponseResult): # ${o.dataDescription!} ${o.exampleCode!} ) ``` -------------------------------- ### Deprecated Documentation Generation (Pre-21.10) Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Example of generating documentation using the older BarSkeletonDoc class, prior to version 21.10. ```java public static void main(String[] args) { ... 省略部分代码 new NettyRunOne() ... ... .startup(); // 生成对接文档 BarSkeletonDoc.me().buildDoc(); } ``` -------------------------------- ### Generating Documentation and Client Code Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Example of setting up IoGameDocumentHelper to generate text documentation and TypeScript client联调 code. This includes adding an error code class and specifying document generators. ```java public static void main(String[] args) { // 添加枚举错误码 class,用于生成错误码相关信息 IoGameDocumentHelper.addErrorCodeClass(GameCode.class); // 添加文档生成器,文本文档 IoGameDocumentHelper.addDocumentGenerate(new TextDocumentGenerate()); // 添加文档生成器,Ts 联调代码生成 IoGameDocumentHelper.addDocumentGenerate(new TypeScriptDocumentGenerate()); // 生成文档 IoGameDocumentHelper.generateDocument(); } ``` -------------------------------- ### Example Usage Comment Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_void.txt A comment block demonstrating how to use the `of_${actionMethodName}` function with a business data object. ```GDScript # ${bizDataComment} var ${bizDataName}: ${bizDataType} = ... ${actionSimpleName}.of${actionMethodName}(${bizDataName}); ``` -------------------------------- ### Register All Broadcast Listeners Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/csharp/broadcast_action.txt Initializes listeners for all defined broadcast events. This method should be called during game setup. ```csharp Listen${o.methodName}(result => { var mergeTitle = CmdKit.ToString(result.GetCmdMerge()); var title = CmdKit.GetBroadcastTitle(result.GetCmdMerge()); <% if (o.exampleCodeAction == null) { %> IoGameSetting.GameGameConsole.Log($"{mergeTitle}, {title}"); <% } else { %> ${originalCode(o.exampleCodeAction)} IoGameSetting.GameGameConsole.Log($"{mergeTitle}, {title}, {value}"); <%}%> }); ``` -------------------------------- ### Check and Get Action Annotations Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Shows how to check for the presence of an annotation and retrieve an annotation instance from an ActionCommand. Requires an ActionCommand object obtained from FlowContext. ```java ActionCommand actionCommand = flowContext.getActionCommand(); bool contain = actionCommand.containAnnotation(DisableDebugInout.class); var annotation = actionCommand.getAnnotation(DisableDebugInout.class); ``` -------------------------------- ### EnterRoomOperationHandler Verification Logic Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Example of `EnterRoomOperationHandler` implementing `processVerify`. This method controls entry into a room, checking for available seats and player score before allowing the `process` method to execute. If conditions are not met, an error code is sent to the client. ```java public final class EnterRoomOperationHandler implements OperationHandler { @Override public boolean processVerify(PlayerOperationContext context) { // assert room spaceSize Room room = context.getRoom(); GameCode.roomSpaceSizeNotEnough.assertTrue(room.hasSeat()); long userId = context.getUserId(); long score = AccountKit.getScore(userId); return score > 500; } @Override public void process(PlayerOperationContext context) { Room room = context.getRoom(); ... enterRoom } } ``` -------------------------------- ### Implement Logic Server Startup with AbstractBrokerClientStartup Source: https://context7.com/iohao/iogame/llms.txt Extends AbstractBrokerClientStartup to create a game logic server that connects to the broker gateway. Configures the business framework and the broker client builder. Ensure the appName and tag are set appropriately for server identification. ```java import com.iohao.game.action.skeleton.core.BarSkeleton; import com.iohao.game.action.skeleton.core.BarSkeletonBuilderParamConfig; import com.iohao.game.bolt.broker.client.AbstractBrokerClientStartup; import com.iohao.game.bolt.broker.core.client.BrokerAddress; import com.iohao.game.bolt.broker.core.client.BrokerClient; import com.iohao.game.bolt.broker.core.client.BrokerClientBuilder; public class GameLogicServer extends AbstractBrokerClientStartup { @Override public BarSkeleton createBarSkeleton() { // Configure business framework BarSkeletonBuilderParamConfig config = new BarSkeletonBuilderParamConfig() .scanActionPackage(GameAction.class) .scanActionPackage(RoomAction.class); return config.createBuilder() .addInOut(new DebugInOut()) .build(); } @Override public BrokerClientBuilder createBrokerClientBuilder() { // Configure broker client return BrokerClient.newBuilder() // Logic server identifier tag (same tag = same type) .appName("game-logic-server") // Unique tag for this logic server type .tag("game"); } @Override public BrokerAddress createBrokerAddress() { // Gateway address - default localhost:10200 return new BrokerAddress("127.0.0.1", 10200); } } ``` -------------------------------- ### Generate Client SDKs and Documentation Source: https://context7.com/iohao/iogame/llms.txt Configure and generate client SDKs for TypeScript, C#, and GDScript, along with broadcast documentation. Ensure business frameworks are configured first. ```java import com.iohao.game.action.skeleton.core.doc.BroadcastDocumentBuilder; import com.iohao.game.action.skeleton.core.doc.IoGameDocumentHelper; import com.iohao.game.action.skeleton.core.doc.TypeScriptDocumentGenerate; import com.iohao.game.action.skeleton.core.doc.CsharpDocumentGenerate; public class DocumentGeneration { public static void main(String[] args) { // Configure business frameworks first yourListLogic().forEach(BrokerClientStartup::createBarSkeleton); // Add broadcast documentation IoGameDocumentHelper.addBroadcastDocument( BroadcastDocumentBuilder.newBuilder(CmdInfo.of(1, 50)) .setDataClass(PlayerJoined.class) .setDescription("Player joined the room") ); // Generate TypeScript SDK for Cocos Creator TypeScriptDocumentGenerate tsGenerate = new TypeScriptDocumentGenerate(); tsGenerate.setPath("/path/to/cocos/project/assets/scripts/gen"); tsGenerate.setProtoImportPath("db://assets/scripts/gen/common_pb"); IoGameDocumentHelper.addDocumentGenerate(tsGenerate); // Generate C# SDK for Unity CsharpDocumentGenerate csharpGenerate = new CsharpDocumentGenerate(); csharpGenerate.setPath("/path/to/unity/Assets/Scripts/Gen"); IoGameDocumentHelper.addDocumentGenerate(csharpGenerate); // Generate GDScript for Godot GDScriptDocumentGenerate gdGenerate = new GDScriptDocumentGenerate(); gdGenerate.setPath("/path/to/godot/project/gen"); IoGameDocumentHelper.addDocumentGenerate(gdGenerate); // Execute generation IoGameDocumentHelper.generateDocument(); } } ``` -------------------------------- ### TaskKit Timer Configuration Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Demonstrates how to configure a `Timer` for `TaskKit`. This allows for scheduled task execution within the game. ```java TaskKit.setTimer(new HashedWheelTimer(17, TimeUnit.MILLISECONDS)); ``` -------------------------------- ### Register All Broadcast Listeners Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/broadcast_action.txt Initializes all defined broadcast listeners. This method should be called to start receiving game broadcasts. ```typescript static listener_ioGame() { // all listener ``` -------------------------------- ### Client Boxing and Unboxing Implementation Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Demonstrates how to implement a client that supports boxing and unboxing for various data types like int, long, boolean, String, and List. Shows how to define commands and their request data. ```java // my client,support:int、long、boolean、String、List public final class MyInputCommandRegion extends AbstractInputCommandRegion { @Override public void initInputCommand() { this.inputCommandCreate.cmd = 1; // Client support boxing and unboxing ofCommand(2).setTitle("enterRoom").setRequestData(() -> { // enterRoom long roomId = 2; return roomId; }); // or ofCommand(2).setTitle("enterRoom").setRequestData(() -> { // enterRoom return LongValue.of(2); }); } } // my action @ActionController(1) public final class MyAction { /** * enterRoom * * @param roomId roomId */ @ActionMethod(2) public void enterRoom(long roomId) { } } ``` -------------------------------- ### Configure External Server Builder Source: https://context7.com/iohao/iogame/llms.txt Use DefaultExternalServerBuilder to set up the external server, configure connection types like WebSocket or TCP, and manage access authentication hooks by ignoring or rejecting specific commands. ```java import com.iohao.game.external.core.ExternalServer; import com.iohao.game.external.core.config.ExternalJoinEnum; import com.iohao.game.external.core.netty.DefaultExternalServerBuilder; public class ExternalServerConfig { public static ExternalServer createExternalServer(int port) { // Create builder with external port DefaultExternalServerBuilder builder = DefaultExternalServer.newBuilder(port); // Configure connection type (WebSocket by default) builder.externalJoinEnum(ExternalJoinEnum.WEBSOCKET); // For TCP connections // builder.externalJoinEnum(ExternalJoinEnum.TCP); // Access authentication hook configuration var setting = builder.setting(); var accessHook = setting.getAccessAuthenticationHook(); // Routes that don't require login accessHook.addIgnoreAuthCmd(1, 0); // cmd=1, subCmd=0 (login) accessHook.addIgnoreAuthCmd(1, 1); // cmd=1, subCmd=1 (register) // Reject access to internal-only routes accessHook.addRejectionCmd(99, 1); // cmd=99, subCmd=1 (admin only) return builder.build(); } } ``` -------------------------------- ### Handle Broadcast Notification Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/broadcast_action.txt Example of a callback function for a broadcast listener. It logs the command details and processes specific data if available. ```typescript Listener.listen${o.methodName}(result => { const mergeTitle = CmdKit.toString(result.getCmdMerge()); const title = CmdKit.getBroadcastTitle(result.getCmdMerge()); <% if (o.exampleCodeAction == null) { %> console.log(mergeTitle, title); <% } else { %> ${o.exampleCodeAction!} console.log(mergeTitle, title, value); <%}%> }); ``` -------------------------------- ### Handle Await Result Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_no_param.txt Example of handling the result from an await-based RequestCommand. Checks for success and prints error details if the operation failed. ```gdscript var result := await ${actionSimpleName}.of_await_${actionMethodName}() if result.success(): # ${returnComment} ${exampleCode} else: var error_code := result.get_response_status() print("error_code: ", error_code) print("error_info: ", result.get_error_info()) ``` -------------------------------- ### Create Room with System Creator Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Use `RoomCreateContext.of()` for system-initiated room creation. Use `RoomCreateContext.of(userId)` when a specific user creates the room. ```java RoomCreateContext.of(); // 无房间创建者,通常表示系统创建 RoomCreateContext.of(userId); // 房间创建者为 userId ``` -------------------------------- ### Get User Thread Executors in Java Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Retrieve thread executors associated with a specific user ID using ExecutorRegionKit. Useful for managing user-specific tasks. ```java @Test public void userThreadExecutor() { long userId = 1; ThreadExecutor userThreadExecutor = ExecutorRegionKit.getUserThreadExecutor(userId); userThreadExecutor.execute(() -> { // print 1 log.info("userThreadExecutor : 1"); }); userThreadExecutor.execute(() -> { // print 2 log.info("userThreadExecutor : 2"); }); } ``` ```java @Test public void getUserVirtualThreadExecutor() { long userId = 1; ThreadExecutor userVirtualThreadExecutor = ExecutorRegionKit.getUserVirtualThreadExecutor(userId); userVirtualThreadExecutor.execute(() -> { // print 1 log.info("userVirtualThreadExecutor : 1"); }); userVirtualThreadExecutor.execute(() -> { // print 2 log.info("userVirtualThreadExecutor : 2"); }); } ``` ```java @Test public void getSimpleThreadExecutor() { long userId = 1; ThreadExecutor simpleThreadExecutor = ExecutorRegionKit.getSimpleThreadExecutor(userId); simpleThreadExecutor.execute(() -> { // print 1 log.info("simpleThreadExecutor : 1"); }); simpleThreadExecutor.execute(() -> { // print 2 log.info("simpleThreadExecutor : 2"); }); } ``` -------------------------------- ### Protobuf Class Annotation Warning Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md This example demonstrates a warning generated when a protocol class used in an action method lacks the ProtobufClass annotation, which is required when using ProtoDataCodec. ```java // 该协议类没有添加 ProtobufClass 注解 class Bird { public String name; } @ActionController(1) public class MyAction { @ActionMethod(1) public Bird testObject() { return new Bird(); } } ======== 注意,协议类没有添加 ProtobufClass 注解 ======== class com.iohao.game.action.skeleton.core.action.Bird ``` -------------------------------- ### Configure Business Framework Skeleton with BarSkeletonBuilder Source: https://context7.com/iohao/iogame/llms.txt Constructs the business framework skeleton for a logic server. Configures action controllers, plugins, and exception handlers. Use this to define the core components of your game's business logic. ```java import com.iohao.game.action.skeleton.core.BarSkeleton; import com.iohao.game.action.skeleton.core.BarSkeletonBuilder; import com.iohao.game.action.skeleton.core.BarSkeletonBuilderParamConfig; import com.iohao.game.action.skeleton.core.flow.interal.DebugInOut; import com.iohao.game.action.skeleton.core.flow.interal.TraceIdInOut; public class GameBarSkeletonConfig { public static BarSkeleton createBarSkeleton() { // Parameter configuration for scanning action classes BarSkeletonBuilderParamConfig config = new BarSkeletonBuilderParamConfig() // Scan all ActionController classes in package .scanActionPackage(UserAction.class) .scanActionPackage(GameAction.class); BarSkeletonBuilder builder = config.createBuilder(); // Add debug plugin for development logging builder.addInOut(new DebugInOut()); // Add trace ID plugin for distributed tracing builder.addInOut(new TraceIdInOut()); // Register individual action controllers builder.addActionController(RoomAction.class); // Configure custom FlowContext factory (optional) builder.setFlowContextFactory(MyFlowContext::new); // Build the skeleton return builder.build(); } } // Custom FlowContext with attachment support public class MyFlowContext extends FlowContext { private MyAttachment attachment; @Override @SuppressWarnings("unchecked") public MyAttachment getAttachment() { if (attachment == null) { this.attachment = this.getAttachment(MyAttachment.class); } return this.attachment; } } ``` -------------------------------- ### Describe Broadcast Parameters with BarSkeletonBuilder Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Configures broadcast documentation using `BarSkeletonBuilder`. This allows for detailed descriptions of data classes and parameters for specific broadcast commands like player entry and offline events. ```java private void extractedDco(BarSkeletonBuilder builder) { // UserCmd builder.addBroadcastDoc(BroadcastDoc.newBuilder(UserCmd.of(UserCmd.enterSquare)) .setDataClass(SquarePlayer.class) .setDescription("新玩家加入房间,给房间内的其他玩家广播") ).addBroadcastDoc(BroadcastDoc.newBuilder(UserCmd.of(UserCmd.offline)) .setDataClass(LongValue.class, "userId") .setDescription("有玩家下线了") ); } ``` -------------------------------- ### Create and Execute RequestCommand Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/action_method_void_no_param.txt Use this static method to create a RequestCommand instance and immediately execute it. Ensure the necessary SDK method and command name are correctly provided. ```typescript static of${actionMethodName}(): RequestCommand { return RequestCommand.of${sdkMethodName!}(this.${memberCmdName}).execute(); } ``` -------------------------------- ### ActionController - Defining Route Controllers Source: https://context7.com/iohao/iogame/llms.txt Demonstrates how to define route controllers using the @ActionController annotation. Each controller handles a specific command (cmd) and its methods handle sub-commands (subCmd). ```APIDOC ## POST /api/actions ### Description Handles actions defined by @ActionController and @ActionMethod. The specific action is determined by the cmd and subCmd values. ### Method POST ### Endpoint /api/actions ### Parameters #### Request Body - **cmd** (integer) - Required - The command identifier for the controller. - **subCmd** (integer) - Required - The sub-command identifier for the method. - **data** (object) - Required - The payload for the action, typically a Protobuf serialized object. ### Request Example ```json { "cmd": 1, "subCmd": 0, "data": "base64EncodedProtobufData" } ``` ### Response #### Success Response (200) - **data** (object) - The response payload, typically a Protobuf serialized object. #### Response Example ```json { "data": "base64EncodedProtobufData" } ``` ``` -------------------------------- ### Email Service Event Subscriber Source: https://context7.com/iohao/iogame/llms.txt Subscribes to `UserLoginEvent` without a specific executor, allowing default handling. This example shows how a different logic server (e.g., EmailLogicServer) can process the same event. ```java // Subscriber in EmailLogicServer (different process) @EventBusSubscriber public class EmailEventSubscriber { @EventSubscribe public void sendWelcomeEmail(UserLoginEvent event) { System.out.println("Sending welcome email to user: " + event.userId); // Send daily login reward email } } ``` -------------------------------- ### Get Various Data Types from ResponseMessage Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Demonstrates how to retrieve different data types like objects, integers, longs, strings, and booleans from a ResponseMessage. Use listValue for collections of objects. ```java public void test() { ResponseMessage responseMessage = ...; // object responseMessage.getValue(Student.class); List listValue = responseMessage.listValue(Student.class); // int int intValue = responseMessage.getInt(); List listInt = responseMessage.listInt(); // long long longValue = responseMessage.getLong(); List listLong = responseMessage.listLong(); // String String stringValue = responseMessage.getString(); List listString = responseMessage.listString(); // boolean boolean boolValue = responseMessage.getBoolean(); List listBoolean = responseMessage.listBoolean(); } ``` -------------------------------- ### POST /api/game/action/await Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/action_method.txt Sends a business data object to the game server and returns the result synchronously. ```APIDOC ## POST /api/game/action/await ### Description This endpoint allows sending business data to the game server and receiving the result synchronously using async/await. It handles various data types and list formats. ### Method POST ### Endpoint `/api/game/action/await` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **bizDataName** (protoPrefix${bizDataType}) - Required - The business data to be sent to the game server. ### Request Example ```json { "bizDataName": { /* ... business data ... */ } } ``` ### Response #### Success Response (200) - **ResponseResult** (object) - The result of the game action. #### Response Example ```json { "value": "some_result_value", "status": "success" } ``` ``` -------------------------------- ### User Action for Cross-Server Calls Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Demonstrates how the 'User' game logic server interacts with the 'Home' server using asynchronous module message calls. It shows simplified usage of ResponseMessage for string, string list, and object list retrieval. ```java @ActionController(UserCmd.cmd) public class UserAction { @ActionMethod(UserCmd.userSleep) public void userSleep(FlowContext flowContext) { flowContext.invokeModuleMessageAsync(HomeCmd.of(HomeCmd.name), responseMessage -> { String name = responseMessage.getString(); log.info("{}", name); }); flowContext.invokeModuleMessageAsync(HomeCmd.of(HomeCmd.listName), responseMessage -> { var listName = responseMessage.listString(); log.info("{}", listName); }); flowContext.invokeModuleMessageAsync(HomeCmd.of(HomeCmd.listStudent), responseMessage -> { List studentList = responseMessage.listValue(Student.class); log.info("{}", studentList); }); } } ``` -------------------------------- ### Update and Get FlowContext Metadata Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Shows how to retrieve, modify, and synchronize metadata (attachments) associated with a FlowContext. Use `updateAttachment()` for synchronous updates and `updateAttachmentAsync()` for asynchronous, non-blocking updates to the external game server. ```java void test(MyFlowContext flowContext) { // 获取元信息 MyAttachment attachment = flowContext.getAttachment(); attachment.nickname = "渔民小镇"; // [同步]更新 - 将元信息同步到玩家所在的游戏对外服中 flowContext.updateAttachment(); // [异步无阻塞]更新 - 将元信息同步到玩家所在的游戏对外服中 flowContext.updateAttachmentAsync(); } public class MyFlowContext extends FlowContext { MyAttachment attachment; @Override @SuppressWarnings("unchecked") public MyAttachment getAttachment() { if (Objects.isNull(attachment)) { this.attachment = this.getAttachment(MyAttachment.class); } return this.attachment; } } ``` -------------------------------- ### Create and Execute Void RequestCommand Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_void_no_param.txt Use this method to create an empty RequestCommand and immediately execute it. This is useful for simple, non-parameterized actions. ```gdscript static func of_${actionMethodName}() -> IoGame.RequestCommand: return IoGame.RequestCommand.of_empty(_${memberCmdName}).execute() ``` -------------------------------- ### Execute Game Action with Callback Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/csharp/action_method.txt Use this method to execute a game action and handle the response using a callback function. Ensure the callback is properly defined to process the returned data. ```csharp /// /// ${methodComment} /// /// ${bizDataComment} /// ${returnDataIsList?"list of "} ${returnComment} /// RequestCommand /// /// // ${bizDataComment} /// ${codeEscape(bizDataType)} ${bizDataName} = ...; /// ${actionSimpleName}.of${actionMethodName}(${bizDataName}, result => { /// // ioGame: your biz code. /// // ${returnComment} /// ${exampleCode!} /// result.Log(value); /// }); /// public static RequestCommand Of${actionMethodName}(${bizDataType} ${bizDataName}, CallbackDelegate callback) { <%if (bizDataTypeIsList && !internalBizDataType) {%> var dataList = ${bizDataName}.Cast().ToList(); return RequestCommand.Of${sdkMethodName}(${memberCmdName}, dataList).OnCallback(callback).Execute(); <%} else {%> return RequestCommand.Of${sdkMethodName}(${memberCmdName}, ${bizDataName}).OnCallback(callback).Execute(); <%}%> } ``` -------------------------------- ### Create RequestMessage with CmdInfo in Java Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Simplifies creating request objects for external game servers using the UserSession interface. ```java var cmdInfo = CmdInfo.of(1, 1); RequestMessage request = userSession.ofRequestMessage(cmdInfo); ``` -------------------------------- ### Configure BrokerClient Listener in Java Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Adds a listener to print online/offline information for other logic servers in a multi-process environment. This is part of the AbstractBrokerClientStartup implementation. ```java public class MyLogicServer extends AbstractBrokerClientStartup { ... @Override public BrokerClientBuilder createBrokerClientBuilder() { BrokerClientBuilder builder = BrokerClient.newBuilder(); ... // 添加监听 - 打印其他进程逻辑服的上线与下线信息 builder.addListener(SimplePrintBrokerClientListener.me()); return builder; } } ``` -------------------------------- ### POST /api/game/command/await Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/csharp/action_method.txt Executes a game command and returns the result asynchronously. ```APIDOC ## POST /api/game/command/await ### Description This endpoint allows you to send a command to the game and asynchronously wait for the result. This is useful for operations that require a direct result before proceeding. ### Method POST ### Endpoint /api/game/command/await ### Parameters #### Request Body - **bizData** (object) - Required - The data associated with the business operation. ### Request Example ```json { "bizData": { ... } } ``` ### Response #### Success Response (200) - **ResponseResult** (object) - Contains the result of the operation, potentially including a list of data. - **Data** (object) - The actual data returned, which could be a list of a specific type. ### Code Example ```csharp // Example usage within C# // Assuming 'actionSimpleName', 'actionMethodName', 'bizDataType', 'bizDataName', 'bizDataComment', 'returnDataName', 'returnComment', 'sdkMethodName', 'memberCmdName' are defined elsewhere. // Define the business data ${bizDataType} ${bizDataName} = ...; // Execute the command and await the result var result = await ${actionSimpleName}.ofAwait${actionMethodName}(${bizDataName}); // ioGame: your biz code. // ${returnComment} ${exampleCode!} result.Log(value); ``` ### Error Handling Errors during the asynchronous operation will be thrown as exceptions. ``` -------------------------------- ### Using Generic Types in GameFlowContext Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Demonstrates how to use the generic getRoom and getPlayer methods from GameFlowContext. Room and Player objects no longer require explicit casting when retrieved. ```java GameFlowContext gameFlowContext = ...; // FightRoomEntity 是自定义的 Room 对象 // Room、Player 在使用时,不需要强制转换了 FightRoomEntity room = gameFlowContext.getRoom(); FightPlayerEntity player = gameFlowContext.getPlayer(); ``` -------------------------------- ### POST /api/game/await_action Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method.txt Executes a game action and awaits a response, returning the result directly. ```APIDOC ## POST /api/game/await_action ### Description This endpoint executes a game action with the provided business data and waits for the response, returning the `IoGame.ResponseResult` directly. This is a synchronous-like wrapper around an asynchronous operation. ### Method POST ### Endpoint /api/game/await_action ### Parameters #### Request Body - **bizDataName** (object) - Required - The business data relevant to the action. ### Request Example ```json { "bizDataName": { ... } } ``` ### Response #### Success Response (200) - **IoGame.ResponseResult** (object) - An object containing the result of the game action, including success status and data or error information. #### Response Example ```json { "success": true, "data": { ... } } ``` #### Error Response (non-200) - **IoGame.ResponseResult** (object) - An object containing error details. #### Error Response Example ```json { "success": false, "error_code": 500, "error_info": "Internal Server Error" } ``` ``` -------------------------------- ### Configure External Game Server Cache Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Adds a command to the external game server's cache configuration. Use this to cache frequently accessed business data in the external server's memory for performance gains. ```java private static void extractedExternalCache() { // 框架内置的缓存实现类 DefaultExternalCmdCache externalCmdCache = new DefaultExternalCmdCache(); // 添加到配置中 ExternalGlobalConfig.externalCmdCache = externalCmdCache; // 配置缓存 3-1 externalCmdCache.addCmd(3, 1); } ``` -------------------------------- ### Initialize GameFlowContext with Room Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Create a `GameFlowContext` instance by providing a `Room` object. This context is used in game flow simulations. ```java public void test() { Room room = ...; GameFlowContext context = GameFlowContext.of(room); ... 省略部分代码 } ``` -------------------------------- ### Listen for Broadcast Events Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/csharp/broadcast_action.txt Sets up a listener for a specific broadcast command. The callback function is executed when the broadcast is received. ```csharp Listener.listen${o.methodName}(result => { // ${o.dataDescription!"broadcast notification"} ${o.exampleCode!} }); ``` -------------------------------- ### Implement Broadcast Listener Callback Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/broadcast_action.txt Sets up a listener for a specific broadcast command. The callback function is executed when the command is received. ```typescript static listen${o.methodName}(callback: (result: ResponseResult) => void) { // ${o.dataDescription!} ListenCommand.of(this.${o.cmdMethodName}_${o.cmd}_${o.subCmd}, callback); } ``` -------------------------------- ### Execute Command with Callback Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_no_param.txt This endpoint allows executing a game command and receiving the result via a callback function. ```APIDOC ## POST /iohao/iogame/command ### Description Executes a game command and provides the result to a callback function. ### Method POST ### Endpoint /iohao/iogame/command ### Parameters #### Query Parameters - **callback** (Callable) - Required - The function to be called with the command result. ### Request Body (Implicitly defined by the `of_empty` method and `memberCmdName`) ### Request Example ```json { "actionMethodName": "exampleAction", "memberCmdName": "exampleCommand" } ``` ### Response #### Success Response (200) - **IoGame.RequestCommand** (object) - An object representing the command request. #### Response Example ```json { "command_id": "some_id", "status": "pending" } ``` ``` -------------------------------- ### RequestCommand.of${actionMethodName}() Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/action_method_void_no_param.txt This method constructs and executes a RequestCommand for a specific action. It's a static factory method that simplifies command creation and execution. ```APIDOC ## Static Method for RequestCommand ### Description This static method `of${actionMethodName}` creates and executes a `RequestCommand` using the provided `memberCmdName` and `sdkMethodName`. ### Method `static of${actionMethodName}()` ### Endpoint N/A (Client-side SDK method) ### Parameters None directly, but relies on class members `memberCmdName` and `sdkMethodName`. ### Request Example ```typescript // Assuming RequestCommand, actionSimpleName, and actionMethodName are defined elsewhere const command = YourClass.of${actionMethodName}(); ``` ### Response - **RequestCommand** (object) - The executed command object. ### Response Example ```json // The actual return type is RequestCommand, which is an object. // Example structure of a RequestCommand object (implementation specific): { "commandName": "${memberCmdName}", "parameters": {}, "isExecuted": true } ``` ``` -------------------------------- ### POST /api/game/action Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method.txt Executes a game action with provided business data and a callback for response handling. ```APIDOC ## POST /api/game/action ### Description This endpoint allows you to send business data to perform a specific action within the game and provides a callback to handle the asynchronous response. ### Method POST ### Endpoint /api/game/action ### Parameters #### Request Body - **bizDataName** (object) - Required - The business data relevant to the action. - **callback** (function) - Required - A function to be called with the game's response result. ### Request Example ```json { "bizDataName": { ... }, "callback": function(result) { ... } } ``` ### Response #### Success Response (200) - **IoGame.RequestCommand** (object) - An object representing the command sent to the game server. #### Response Example ```json { "command_id": "123e4567-e89b-12d3-a456-426614174000", "status": "pending" } ``` ``` -------------------------------- ### Execute Game Request with Await (List Data Type) Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method.txt Asynchronously sends a game request with a list of business data. The data is prepared as a ByteValueList and then executed. ```gdscript var _message := IoGame.Proto.ByteValueList.new() for _value in ${bizDataName}: _message.add_values(_value.to_bytes()) var _request := IoGame.RequestCommand.of(_${memberCmdName}, _message.to_bytes()) _request.data_source = ${bizDataName} return await IoGame.RequestCommand.of_await_request_command(_request) ``` -------------------------------- ### POST /api/game/command Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/csharp/action_method.txt Executes a game command with a callback for results. ```APIDOC ## POST /api/game/command ### Description This endpoint allows you to send a command to the game and receive a response via a callback function. It is suitable for operations where immediate synchronous results are not required. ### Method POST ### Endpoint /api/game/command ### Parameters #### Request Body - **bizData** (object) - Required - The data associated with the business operation. - **callback** (function) - Required - A callback function to handle the response. ### Request Example ```json { "bizData": { ... }, "callback": "function(result) { ... }" } ``` ### Response This endpoint does not return a direct response body. Results are handled by the provided callback function. ### Code Example ```csharp // Example usage within C# // Assuming 'actionSimpleName', 'actionMethodName', 'bizDataType', 'bizDataName', 'bizDataComment', 'returnDataName', 'returnComment', 'sdkMethodName', 'memberCmdName' are defined elsewhere. // Define the business data ${bizDataType} ${bizDataName} = ...; // Execute the command with a callback ${actionSimpleName}.of${actionMethodName}(${bizDataName}, result => { // ioGame: your biz code. // ${returnComment} ${exampleCode!} result.Log(value); }); ``` ### Error Handling Errors are typically handled within the callback function or through exceptions thrown by the underlying RequestCommand execution. ``` -------------------------------- ### Execute RequestCommand with Callback Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_no_param.txt Use this method to execute a command and handle the response via a callback function. The callback receives a IoGame.ResponseResult. ```gdscript static func of_actionMethodName(callback: Callable) -> IoGame.RequestCommand: return IoGame.RequestCommand.of_empty(_memberCmdName).on_callback(callback).execute() ``` -------------------------------- ### IoGame.RequestCommand Generation Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method_void.txt This snippet demonstrates the generation of IoGame.RequestCommand objects for various data types and their execution. ```APIDOC ## POST /iohao/iogame ### Description Generates and executes an IoGame RequestCommand based on the provided business data. ### Method POST ### Endpoint /iohao/iogame ### Parameters #### Request Body - **bizDataName** (string) - Required - The name of the business data object. - **bizDataComment** (string) - Required - A comment describing the business data. - **bizDataType** (string) - Required - The data type of the business data. - **actionSimpleName** (string) - Required - The simple name of the action. - **actionMethodName** (string) - Required - The method name for the action. - **internalBizDataType** (boolean) - Optional - Flag indicating if the business data type is internal. - **bizDataTypeIsList** (boolean) - Optional - Flag indicating if the business data type is a list. - **sdkMethodName** (string) - Required - The SDK method name to use. - **memberCmdName** (string) - Required - The member command name. ### Request Example ```json { "bizDataName": "playerData", "bizDataComment": "Player game statistics", "bizDataType": "PlayerStats", "actionSimpleName": "Player", "actionMethodName": "updateStats", "internalBizDataType": false, "bizDataTypeIsList": false, "sdkMethodName": "updatePlayerStats", "memberCmdName": "PLAYER_STATS" } ``` ### Response #### Success Response (200) - **IoGame.RequestCommand** (object) - The generated and executed request command. #### Response Example ```json { "commandId": "cmd_12345", "status": "executed" } ``` ``` -------------------------------- ### Execute Tasks with FlowContext in Java Source: https://github.com/iohao/iogame/blob/main/changeLog_ioGame.md Execute tasks using the FlowContext, which supports full-link tracing. Includes methods for standard and virtual thread executors. ```java void executor() { // 该方法具备全链路调用日志跟踪 flowContext.execute(() -> { log.info("用户线程执行器"); }); // 正常提交任务到用户线程执行器中 // getExecutor() 用户线程执行器 flowContext.getExecutor().execute(() -> { log.info("用户线程执行器"); }); } ``` ```java void executeVirtual() { // 该方法具备全链路调用日志跟踪 flowContext.executeVirtual(() -> { log.info("用户虚拟线程执行器"); }); // 正常提交任务到用户虚拟线程执行器中 // getVirtualExecutor() 用户虚拟线程执行器 flowContext.getVirtualExecutor().execute(() -> { log.info("用户虚拟线程执行器"); }); // 示例演示 - 更新元信息(可以使用虚拟线程执行完成一些耗时的操作) flowContext.executeVirtual(() -> { log.info("用户虚拟线程执行器"); // 更新元信息 flowContext.updateAttachment(); // ... ... 其他业务逻辑 }); } ``` -------------------------------- ### Execute Request with Callback Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/ts/action_method.txt Use this method to send a request and handle the response using a callback function. It supports single objects and lists of objects, converting them to binary format as needed. ```typescript static of${actionMethodName}(${bizDataName}: ${protoPrefix}${bizDataType}, callback: (result: ResponseResult) => void): RequestCommand { <% if (internalBizDataType) { %> return RequestCommand.of${sdkMethodName!}(this.${memberCmdName}, ${bizDataName}).onCallback(callback).execute(); <% } else if (bizDataTypeIsList) { %> const dataList = ${bizDataName}.map(o => { return toBinary(${protoPrefix}${actualTypeName}Schema, o); }); const requestCommand = RequestCommand.of${sdkMethodName}(this.${memberCmdName}, dataList).onCallback(callback); requestCommand.dataSource = ${bizDataName}; return requestCommand.execute(); <% } else { %> const data = toBinary(${protoPrefix}${bizDataType}Schema, ${bizDataName}); const requestCommand = RequestCommand.of(this.${memberCmdName}, data).onCallback(callback); requestCommand.dataSource = ${bizDataName}; return requestCommand.execute(); <% } %> } ``` -------------------------------- ### Execute Game Request with Await (Single Data Type) Source: https://github.com/iohao/iogame/blob/main/widget/generate-code/src/main/resources/generate/gdscript/action_method.txt Asynchronously sends a game request with a single piece of business data. The data is converted to bytes and then executed. ```gdscript var _data := ${bizDataName}.to_bytes() var _request := IoGame.RequestCommand.of(_${memberCmdName}, _data) _request.data_source = ${bizDataName} return await IoGame.RequestCommand.of_await_request_command(_request) ``` -------------------------------- ### User Login Event Publisher Source: https://context7.com/iohao/iogame/llms.txt Publishes `UserLoginEvent` asynchronously to all subscribers, synchronously to local subscribers, or to a single instance across logic servers using `FlowContext.fire()`, `fireLocalSync()`, and `fireAny()` respectively. The event class must be `Serializable`. ```java import com.iohao.game.action.skeleton.eventbus.EventBusSubscriber; import com.iohao.game.action.skeleton.eventbus.EventSubscribe; import com.iohao.game.action.skeleton.eventbus.ExecutorSelector; import java.io.Serializable; // Event message class - must be Serializable for cross-process communication public class UserLoginEvent implements Serializable { public final long userId; public final String loginTime; public UserLoginEvent(long userId) { this.userId = userId; this.loginTime = java.time.LocalDateTime.now().toString(); } } // Publisher action @ActionController(1) public class UserAction { @ActionMethod(1) public String onLogin(FlowContext flowContext) { long userId = flowContext.getUserId(); // Fire event to all subscribers (async, cross-process) flowContext.fire(new UserLoginEvent(userId)); // Fire sync to local process subscribers only flowContext.fireLocalSync(new UserLoginEvent(userId)); // Fire to only one instance of each logic server type flowContext.fireAny(new UserLoginEvent(userId)); return "login_success"; } } ```