### Configure and Start Code Generation Source: https://iohao.github.io/ionet/en/docs/extension_module/generate_code This example shows how to add implementations for document generation and then start the generation process. Ensure all necessary implementations are added before calling generateDocument(). ```java public final class GenerateTest { static void main() { ... DocumentHelper.addDocumentGenerate(new GDScriptDocumentGenerate()); DocumentHelper.generateDocument(); } } ``` -------------------------------- ### High-Level Code Generation Setup Source: https://iohao.github.io/ionet/en/docs/examples/code_generate This example demonstrates the main setup for code generation within a Java application. It configures locale, access authentication, loads business logic servers, and initiates the generation of actions, broadcasts, error codes, and proto files. ```java public final class GenerateTest { ... static void main() { // i18n: CHINA or US Locale.setDefault(Locale.US); CoreGlobalConfig.setting.parseDoc = true; /* * ExternalServer accessAuthentication * cn: 对外服访问权限,不生成权限控制的 action */ SdkApplication.extractedAccess(); DocumentAccessAuthentication reject = ExternalGlobalConfig.accessAuthenticationHook::reject; DocumentHelper.setDocumentAccessAuthentication(reject); // Load the business framework of each gameLogicServer // cn: 加载业务逻辑服 SdkApplication.listLogic().forEach(logicServer -> { var builder = BarSkeleton.builder(); logicServer.settingBarSkeletonBuilder(builder); builder.build(); }); /* * 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 DocumentHelper.addErrorCodeClass(ErrorCode.class); // Generate document DocumentHelper.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); } } ``` -------------------------------- ### Install ionet from Source Source: https://iohao.github.io/ionet/en/docs/installation After cloning the repository, navigate into the source directory and install ionet locally using `mvnd` or `mvn`. ```bash mvnd install ``` -------------------------------- ### SDK Setup with IoGameSetting Source: https://iohao.github.io/ionet/en/docs/examples/sdk_ts Configure and start the network connection using IoGameSetting. This includes enabling dev mode, setting the language, defining message callbacks, and specifying the WebSocket URL and net channel. ```typescript export class YourNetConfig { static startNet() { // --------- IoGameSetting --------- ioGameSetting.enableDevMode = true; // China or Us ioGameSetting.language = ioGameLanguage.CHINA; // message callback. cn: 回调监听 ioGameSetting.listenMessageCallback = new YourListenMessageCallback(); // socket ioGameSetting.url = "ws://127.0.0.1:10100/websocket"; ioGameSetting.netChannel = new YourNetChannel(); ioGameSetting.startNet() } } ``` -------------------------------- ### Interactive Console Command Example Source: https://iohao.github.io/ionet/en/docs/extension_module/simulation_client After starting the simulated client, the console becomes interactive, displaying command lists and allowing input to trigger requests. ```text cmd-subCmd ``` -------------------------------- ### Startup Logic Servers Source: https://iohao.github.io/ionet/en/docs/manual/logic_intro Configure and start the logic servers using `RunOne`. Set the list of logic servers to be started using `setLogicServerList`. ```java final class TestOneApplication { static void main() { new RunOne() ... .setLogicServerList(listLogic()) .startup(); } static List listLogic() { return List.of(new DemoLogicServer()); } } ``` -------------------------------- ### Start Client for Verification Source: https://iohao.github.io/ionet/en/docs/manual_high/deploy-multi-process This command starts the client application, which is used to verify the multi-process deployment by sending sample requests and checking the responses. ```bash java -jar one-client/target/one-client.jar ``` -------------------------------- ### Start ionet Server Source: https://iohao.github.io/ionet/en/docs/quick_zero_demo This Java code initializes and starts the ionet server, configuring it to parse source documentation and print output. It sets up the external server port and an embedded Aeron runtime, then starts the server with logic servers. ```java public class DemoApplication { static void main() { // Enable source documentation parsing to display code line numbers. // cn: 开启源码文档解析,以显示代码行数。 CoreGlobalConfig.setting.parseDoc = true; CoreGlobalConfig.setting.print = true; // i18n: US or CHINA Locale.setDefault(Locale.CHINA); // Create the ExternalServer builder and set the port for establishing connections with real players // cn: 创建对外服构建器,并设置与真实玩家建立连接的端口 int port = ExternalGlobalConfig.externalPort; var externalServer = ExternalMapper.builder(port).build(); // Create an EmbeddedAeronRuntime instance and get the Aeron instance // cn: 创建 EmbeddedAeronRuntime 实例并获取 Aeron 实例 var aeron = new EmbeddedAeronRuntime().getAeron(); new RunOne() // aeron .setAeron(aeron) .enableCenterServer() // externalServer. cn: 对外服 .setExternalServer(externalServer) // logicServers. cn: 逻辑服 .setLogicServerList(List.of(new DemoLogicServer())) .startup(); } } // see https://github.com/iohao/ionet-examples/blob/main/ionet-quick-demo/src/main/java/com/iohao/example/quick/EmbeddedAeronRuntime.java public class EmbeddedAeronRuntime { ... } ``` -------------------------------- ### Start the JAR Server Source: https://iohao.github.io/ionet/en/docs/quick_zero_demo Execute this command to run the packaged JAR file. The server typically starts in under a second. Ensure to include the necessary Java VM options for unnamed modules. ```bash java \ --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ --enable-native-access=ALL-UNNAMED \ -jar target/ionet-quick-demo.jar ``` -------------------------------- ### Start External and Logic Services in Same Process Source: https://iohao.github.io/ionet/en/docs/manual/run_one This snippet shows how to configure and start external services and a list of logic services within the same process using RunOne. It requires prior setup of Aeron, external server configuration, and logic server definitions. ```java final class OneApplication { static void main() { ... new RunOne() .setAeron(aeron) .enableCenterServer() .setExternalServer(ofExternalServer()) .setLogicServerList(listLogic()) .startup(); } static ExternalServer ofExternalServer() { var builder = ExternalMapper.builder(ExternalGlobalConfig.externalPort); builder.setJoinEnum(ExternalJoinEnum.WEBSOCKET); return builder.build(); } static List listLogic() { return List.of( new HallLogicServer() , new RoomLogicServer() ); } } ``` -------------------------------- ### Install iohao-sdk Source: https://iohao.github.io/ionet/en/docs/examples/sdk_ts Install the iohao-sdk package using npm. This is the first step to using the TypeScript SDK. ```bash npm i iohao-sdk ``` -------------------------------- ### Start Logic Service Processes Source: https://iohao.github.io/ionet/en/docs/manual_high/deploy-multi-process This command demonstrates starting two independent logic service processes: the book library service and the author service. Both require specific Java VM options for proper initialization. ```bash # Book library logic service java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ --enable-native-access=ALL-UNNAMED \ -jar logic-book-library/target/logic-book-library.jar # Author logic service java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ --enable-native-access=ALL-UNNAMED \ -jar logic-author/target/logic-author.jar ``` -------------------------------- ### Start Simulated Client Source: https://iohao.github.io/ionet/en/docs/extension_module/simulation_client The `ClientRunOne` class is used to start the simulated client. Add custom `InputCommandRegion` implementations using `setInputCommandRegions` before calling `startup()`. ```java public class DemoClient { static void main() { // US or CHINA Locale.setDefault(Locale.US); // closeLog. cn: 关闭模拟请求相关日志 ClientUserConfigs.closeLog(); // Startup Client. cn: 启动模拟客户端 new ClientRunOne() .setInputCommandRegions(List.of(new DemoRegion())) .startup(); } static class DemoRegion extends AbstractInputCommandRegion { @Override public void initInputCommand() { ... } } } ``` -------------------------------- ### Configure and Start ioGame SDK Source: https://iohao.github.io/ionet/en/docs/examples/example_sdk_cocos This class configures and starts the ioGame SDK. It initializes game code, sets up message listeners, configures network settings including the server URL and network channel, and then starts the network connection. Ensure MySimpleListenMessageCallback and MyNetChannel are correctly implemented for custom logic. ```typescript export class MyNetConfig { public static currentTimeMillis: bigint = BigInt(Date.now()); static startNet() { // biz code init GameCode.init(); // listen(); listen() // --------- IoGameSetting --------- ioGameSetting.enableDevMode = true; // China or Us ioGameSetting.language = ioGameLanguage.CHINA; // message callback. 回调监听 ioGameSetting.listenMessageCallback = new MySimpleListenMessageCallback(); // socket ioGameSetting.url = "ws://127.0.0.1:10100/websocket"; ioGameSetting.netChannel = new MyNetChannel(); ioGameSetting.startNet() } } ``` -------------------------------- ### Start Logic Server with RunOne Source: https://iohao.github.io/ionet/en/docs/manual_high/deploy-multi-process This Java code demonstrates how to initialize and start a logic server, such as a Book Library service, using the RunOne framework. It configures Aeron client and registers the logic server. ```java public final class BookLibraryApplication { static void main() { CoreGlobalConfig.setting.parseDoc = true; var aeron = LogicAeronClientFactory.create(); new RunOne() .setAeron(aeron) .setLogicServerList(List.of(new BookLibraryLogicServer())) .startup(); } } ``` -------------------------------- ### Application Startup with Access Control Source: https://iohao.github.io/ionet/en/docs/manual/access_authentication Integrate the access control setup into the main application startup process. ```java class OneApplication { static void main() { extractedAccess(); ... new RunOne() ... .startup(); } } ``` -------------------------------- ### Verify Maven Installation Source: https://iohao.github.io/ionet/en/docs/installation After installing Maven, verify the installation by checking the version and configuration in your terminal. ```text Apache Maven 3.9.11 (3e54c93a704957b63ee3494413a2b544fd3d825b) Maven home: /usr/local/Cellar/maven/3.9.11/libexec Java version: 25, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-25.jdk/Contents/Home Default locale: zh_CN_#Hans, platform encoding: UTF-8 OS name: "mac os x", version: "26.0.1", arch: "x86_64", family: "mac" ``` -------------------------------- ### Logic Server Action Implementation Source: https://iohao.github.io/ionet/en/docs/communication/request_multiple_response This is an example of a logic server action that can be called by the request/multiple_response model. It increments a value and returns it. Multiple instances of this server can be started for load balancing. ```java @ActionController(InternalCmd.cmd) public class InternalAction { AtomicInteger inc = new AtomicInteger(1); @ActionMethod(InternalCmd.intAction) private int intAction(int value) { return value + inc.getAndIncrement(); } } ``` -------------------------------- ### Configure and Start ioGame SDK Source: https://iohao.github.io/ionet/en/docs/examples/example_sdk_vue This class configures and starts the ioGame SDK. It initializes business code, sets up the network channel with a specified URL, and registers a custom message listener. Ensure the `ioGameSetting.url` points to your WebSocket server. ```typescript export class MyNetConfig { public static currentTimeMillis: bigint = BigInt(Date.now()); static startNet() { // biz code init GameCode.init(); listen(); // --------- IoGameSetting --------- ioGameSetting.enableDevMode = true; // China or Us ioGameSetting.language = ioGameLanguage.CHINA; // message callback. 回调监听 ioGameSetting.listenMessageCallback = new MySimpleListenMessageCallback(); // socket ioGameSetting.url = "ws://127.0.0.1:10100/websocket"; ioGameSetting.netChannel = new MyNetChannel(); ioGameSetting.startNet() } } ``` -------------------------------- ### Configure and Start Domain Events Source: https://iohao.github.io/ionet/en/docs/extension_module/domain_event Sets up domain event handling by adding multiple event handlers for different scenarios like sending emails, going home, and putting a student to sleep. It then starts the domain event application. ```java public class StudentDomainEventTest { DomainEventApplication domainEventApplication; @AfterEach public void tearDown() { domainEventApplication.stop(); } @BeforeEach public void setUp() { var setting = new DomainEventSetting(); setting.addEventHandler(new StudentEmailEventHandler1()); setting.addEventHandler(new StudentGoHomeEventHandler2()); setting.addEventHandler(new StudentSleepEventHandler3()); domainEventApplication = new DomainEventApplication(); domainEventApplication.startup(setting); } @Test public void testEventSend() { new StudentEo(1).send(); } } ``` -------------------------------- ### GDScript SDK Configuration Source: https://iohao.github.io/ionet/en/docs/examples/sdk_godot Configure SDK settings, including development mode, language, and message callbacks. This setup is essential for initializing the network channel and starting the SDK. ```gdscript class_name MyNetConfig extends RefCounted static var _socket: MyNetChannel = MyNetChannel.new() static var current_time_millis: int = 0 static func start_net(): # --------- IoGameSetting --------- var setting := IoGame.IoGameSetting setting.enable_dev_mode = true setting.set_language(IoGame.IoGameLanguage.Us) # message callback. cn: 回调监听 setting.listen_message_callback = MyListenMessageCallback.new() # set socket. cn: 设置网络连接 setting.net_channel = _socket socket_init() setting.start_net() static func poll(): _socket.poll() static var _heartbeat_message_bytes := IoGame.Proto.ExternalMessage.new().to_bytes() static var _heartbeat_counter: int = 1 static func send_idle() -> void: _heartbeat_counter += 1 #print("-------- ..HeartbeatMessage {%s}" % [_heartbeat_counter]) IoGame.IoGameSetting.net_channel.write_and_flush_byte(_heartbeat_message_bytes) class MyListenMessageCallback extends IoGame.ListenMessageCallback: func on_idle_callback(message: Proto.ExternalMessage): var data_bytes := message.get_data() var long_value := IoGame.Proto.LongValue.new() long_value.from_bytes(data_bytes) # Synchronize the time of each heartbeat with that of the server. # cn: 每次心跳与服务器的时间同步 MyNetConfig.current_time_millis = long_value.get_value() class MyNetChannel extends IoGame.SimpleNetChannel: var _last_state: WebSocketPeer.State = WebSocketPeer.State.STATE_CLOSED var _socket: WebSocketPeer = WebSocketPeer.new() var _url: String = "ws://127.0.0.1:10100/websocket" var on_open: Callable = func(): print("on_open") var on_connecting: Callable = func(): print("on_connecting") var on_connect_error: Callable = func(error: int): print("on_connect_error:", error) var on_closing: Callable = func(): print("on_closing") var on_closed: Callable = func(): print("on_closed") func prepare() -> void: if _url == null or _url.is_empty(): _url = IoGame.IoGameSetting.url var error: int = _socket.connect_to_url(_url) if error != 0: on_connect_error.call(error) return _last_state = _socket.get_ready_state() func write_and_flush_byte(bytes: PackedByteArray) -> void: _socket.send(bytes) func poll() -> void: if _socket.get_ready_state() != WebSocketPeer.State.STATE_CLOSED: _socket.poll() while _socket.get_available_packet_count() > 0: var packet := _socket.get_packet() var message := IoGame.Proto.ExternalMessage.new() message.from_bytes(packet) self.accept_message(message) var state: WebSocketPeer.State = _socket.get_ready_state() if _last_state == state: return _last_state = state match state: WebSocketPeer.State.STATE_OPEN: on_open.call() WebSocketPeer.State.STATE_CONNECTING: on_connecting.call() WebSocketPeer.State.STATE_CLOSING: on_closing.call() WebSocketPeer.State.STATE_CLOSED: on_closed.call() _: printerr("Socket Unknown Status.") ``` -------------------------------- ### Initialize and Start ioGame SDK Source: https://iohao.github.io/ionet/en/docs/examples/example_sdk_godot_charp This C# code initializes the ioGame SDK, configures network settings, sets up message callbacks and console logging, and starts the network connection. It includes logic for login verification and a heartbeat mechanism. ```csharp 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); } } } ``` -------------------------------- ### Install ionet-ai to Project for Codex CLI Source: https://iohao.github.io/ionet/en/docs/ionet-ai Run the installation script from the ionet-ai repository root to integrate the knowledge base into your target ionet project. This sets up necessary files for Codex CLI. ```bash bash scripts/install-project.sh --project /path/to/your-project ``` -------------------------------- ### Start Aggregation Process Source: https://iohao.github.io/ionet/en/docs/manual_high/deploy-multi-process This command starts the main aggregation process (one-application) using Java. It includes flags to open specific Java modules and enable native access, necessary for running the MediaDriver and other core components. ```bash java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ --enable-native-access=ALL-UNNAMED \ -jar one-application/target/one-application.jar ``` -------------------------------- ### Start Vue Development Server Source: https://iohao.github.io/ionet/en/docs/examples/example_sdk_vue Launch the Vue.js development server to run the application. This command starts a local server and typically opens the application in your default browser. ```bash npm run dev ``` -------------------------------- ### VM Options for DemoApplication Source: https://iohao.github.io/ionet/en/docs/quick_zero_demo These VM options are required when starting the DemoApplication. They enable necessary access for the Java runtime environment. ```bash --add-opens java.base/jdk.internal.misc=ALL-UNNAMED --enable-native-access=ALL-UNNAMED ``` -------------------------------- ### Install Dependencies with npm Source: https://iohao.github.io/ionet/en/docs/examples/example_sdk_vue Install the required Node.js dependencies for the Vue project. This command should be run in the project's root directory. ```bash npm install ``` -------------------------------- ### Debug Log Output Example 1 Source: https://iohao.github.io/ionet/en/docs/core_plugin/action_debug This is an example of the console log output generated by the DebugInOut plugin for a specific request. ```text ┏━━ Debug.(HallAction.java:18) ━━ [UserMessage loginVerify(String jwt)] ━━ [31-1] ━━ [tag:HallLogicServer, serverId:5656645] ━━━━ ┣ userId: 1378604058 ┣ 参数: Michael Jackson ┣ 响应: UserMessage(id=1378604058, nickname=Jack) ┣ 耗时: 1 ms ┗━━ [ionetVersion] ━━ [线程:User-8-1] ━━ [连接方式:WebSocket] ━━ [traceId:1761556037925] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` -------------------------------- ### Comprehensive Thread Monitoring Example Source: https://iohao.github.io/ionet/en/docs/core_plugin/action_thread_monitor Periodically check thread metrics and trigger alerts when a dangerous threshold is exceeded. This example syncs metrics to logs every 2 minutes. ```java var threadMonitorInOut = new ThreadMonitorInOut(); builder.addInOut(threadMonitorInOut); ThreadMonitorInOut.ThreadMonitorRegion region = threadMonitorInOut.getRegion(); ExecutorKit.newSingleScheduled("Scheduled").scheduleAtFixedRate(() -> { System.out.println(region); region.forEach(threadMonitor -> { LongAdder executeCount = threadMonitor.executeCount(); long avgTime = threadMonitor.getAvgTime(); int countRemaining = threadMonitor.countRemaining(); String name = threadMonitor.name(); LongAdder totalTime = threadMonitor.totalTime(); long dangerous = 8000; if (avgTime * countRemaining > dangerous) { // your code } }); }, 2, 2, TimeUnit.MINUTES); ``` -------------------------------- ### Start Multiple External Servers Source: https://iohao.github.io/ionet/en/docs/manual/external_intro Use this to configure and start multiple external servers supporting different protocols (WEBSOCKET, TCP, UDP) in one process. Ensure the EnterpriseRunOne class is properly initialized with the list of external servers. ```java final class TestOneApplication { static void main() { new EnterpriseRunOne() .setExternalServer(externalServerList) ... .startup(); } static List listExternalServer() { return List.of( ofExternalServer(ExternalJoinEnum.WEBSOCKET) , ofExternalServer(ExternalJoinEnum.TCP) , ofExternalServer(ExternalJoinEnum.UDP) ); } static ExternalServer ofExternalServer(ExternalJoinEnum join) { int port = join.cocPort(ExternalGlobalConfig.externalPort); var externalServerBuilder = MyExternalServer.builder(port, join); return externalServerBuilder.build(); } } ``` -------------------------------- ### Example URL Mapping Source: https://iohao.github.io/ionet/en/docs/manual/cmd Demonstrates how a URL maps to a main route (@ActionController) and a sub route (@ActionMethod). ```plaintext URL: https://ip:port/user/hello ``` -------------------------------- ### Comprehensive Delayed Task Example Source: https://iohao.github.io/ionet/en/docs/kit/delay_task A detailed example demonstrating the creation of a delayed task with a custom listener, conditional time modification, and enhancement of the listener's behavior. This illustrates how to integrate business logic with delayed tasks. ```java public void example() { DelayTask delayTask = DelayTaskKit.of(new ShootTaskListener("Enemy")) .plusTimeMillis(1500) .task(); if (RandomKit.randomBoolean()) { delayTask.minusTime(Duration.ofMillis(500)); ShootTaskListener shootTaskListener = delayTask.getTaskListener(); shootTaskListener.setLuck(true); } } @Slf4j final class ShootTaskListener implements TaskListener { final String targetEntity; boolean luck; int attack = 10; ShootTaskListener(String targetEntity) { this.targetEntity = targetEntity; } @Override public void onUpdate() { int value = luck ? attack * 2 : attack; log.info("value", value); } } ``` -------------------------------- ### Request/Response Client Usage (C#) Source: https://iohao.github.io/ionet/en/docs/manual/communication_model Example of how a client uses the SDK to make a request/response call and process the returned data. ```csharp // C# Code public void TestHello() { var name = "Michael Jackson"; MyAction.OfHello(name, result => { var data = result.GetString(); result.Log(data); }); } ``` -------------------------------- ### Clone ionet Repository Source: https://iohao.github.io/ionet/en/docs/installation To install ionet from source and try unreleased features, clone the official GitHub repository. ```bash git clone https://github.com/iohao/ionet.git ``` -------------------------------- ### Action Business Code Example Source: https://iohao.github.io/ionet/en/docs/manual_high/data_protocol This example demonstrates a business logic class (`JsonAction`) that processes a `HelloMessage`. The `HelloMessage` class retains the `ProtobufClass` annotation, which is ignored when a JSON codec is active, allowing for protocol-agnostic business code. ```java @ActionController(19) public class JsonAction { @ActionMethod(1) public HelloMessage hello(HelloMessage message) { message.name = message.name + ",hello json"; return message; } } ``` ```java @ProtobufClass @FieldDefaults(level = AccessLevel.PUBLIC) public class HelloMessage { public String name; } ``` -------------------------------- ### Action Controller Example Source: https://iohao.github.io/ionet/en/docs/manual/external_message Illustrates how an action controller returns a new HelloMessage object within the ExternalMessage.data. ```java @ActionController(1) public class DemoAction { @ActionMethod(0) public HelloMessage here(HelloMessage message) { HelloMessage newHelloMessage = ... return newHelloMessage; } } ``` -------------------------------- ### Configure JSON Codec for Client Source: https://iohao.github.io/ionet/en/docs/manual_high/data_protocol Initialize the client application with the custom JSON codec by calling `DataCodecManager.setDataCodec(new JsonDataCodec())` before starting the client. ```java class OneClient { static void main() { DataCodecManager.setDataCodec(new JsonDataCodec()); new ClientRunOne() ... .startup(); } } ``` -------------------------------- ### Send String List Example Source: https://iohao.github.io/ionet/en/docs/communication/example_communication Use `sendStringList` to send a list of strings. Ensure the `InternalCmd` is correctly defined for string list actions. ```java @ActionMethod(FlowContextSendCmd.sendStringList) private boolean sendStringList(FlowContext flowContext) { var cmdInfo = InternalCmd.of(InternalCmd.sendStringListAction); List dataList = List.of("hello", "ionet"); flowContext.sendListString(cmdInfo, dataList); return true; } ``` -------------------------------- ### Get Request Parameters in OnExternal Extension Source: https://iohao.github.io/ionet/en/docs/communication/on_external Access request parameters within an OnExternal extension's `process` method. This example shows how to get user session data and set an attachment. ```java public final class AttachmentUpdateOnExternal implements OnExternal { @Override public void process(byte[] payload, int payloadLength, OnExternalContext context) { var userSession = context.getUserSession(); if (userSession != null) { userSession.setAttachment(ByteKit.getPayload(payload, payloadLength)); } else { context.response().setError(ActionErrorEnum.dataNotExist); } } ... } ``` -------------------------------- ### Add run-one Dependency to pom.xml Source: https://iohao.github.io/ionet/en/docs/manual/external_intro Include the 'run-one' dependency in your pom.xml to get started with the framework, which bundles both external and logic servers. ```xml com.iohao.net run-one ${ionet.version} ``` -------------------------------- ### Start External Server with TCP Source: https://iohao.github.io/ionet/en/docs/manual/external_tcp Configure the external server to use TCP by setting the join enum. This builder pattern is used to construct the server. ```java @UtilityClass public class MyExternalServer { ... public ExternalServerBuilder builder(int port, ExternalJoinEnum joinEnum) { var builder = ExternalMapper.builder(port); builder.setJoinEnum(joinEnum); return builder; } } class OneApplication { static void main() { var externalServer = MyExternalServer.builder( ExternalGlobalConfig.externalPort , ExternalJoinEnum.TCP ).build(); new RunOne() ... .setExternalServer(externalServer) .startup(); } } ``` -------------------------------- ### Enable JSR380 validation in application Source: https://iohao.github.io/ionet/en/docs/manual/jsr380 Enable the validator globally by setting `CoreGlobalConfig.setting.validator` to true before starting the application. This is a one-time setup for the application. ```java class OneApplication { static void main() { CoreGlobalConfig.setting.validator = true; ... new RunOne() ... .startup(); } } ``` -------------------------------- ### Monitor Room Game State Changes Source: https://iohao.github.io/ionet/en/docs/kit/property_change_listener An example of using property listeners to monitor changes in a room's game state. It triggers different business methods based on the new game status, such as starting or settling the game. ```java public class FairRoom extends SimpleRoom { ... final ObjectProperty gameStatus = new ObjectProperty<>(GameStatus.NONE); private void extractedInitGameStatus() { this.gameStatus.addListener((observable, oldValue, newValue) -> { switch (newValue) { case START -> nextRound(); case SETTLE -> settle(); } }); } public void changeGameStatus(GameStatus status) { this.executeTask(() -> this.gameStatus.set(status)); } public void changeGameStatus(GameStatus status, long millis) { this.executeDelayTask(() -> this.gameStatus.set(status), millis); } } public enum GameStatus { NONE, START, SETTLE } ``` -------------------------------- ### SDK Setup in C# Source: https://iohao.github.io/ionet/en/docs/examples/sdk_csharp Configures network settings, including development mode, language, message callbacks, and socket initialization. Ensure IoGameSetting.NetChannel is set to your network communication implementation. ```csharp public abstract class YourNetConfig { public static void StartNet() { // --------- IoGameSetting --------- IoGameSetting.EnableDevMode = true; // China or Us IoGameSetting.SetLanguage(IoGameLanguage.China); // message callback. cn: 回调监听 IoGameSetting.ListenMessageCallback = new YourListenMessageCallback(); // Print. cn: 打印 IoGameSetting.GameGameConsole = new YourGameConsole(); // socket SocketInit(); IoGameSetting.StartNet(); } private static void SocketInit() { IoGameSetting.Url = "ws://127.0.0.1:10100/websocket"; // Setting up the Network Communication Implementation Class. // cn: 设置网络通信实现类。 IoGameSetting.NetChannel = new YourWebSocket(); } } ``` -------------------------------- ### Configure Client Startup and Connection Source: https://iohao.github.io/ionet/en/docs/extension_module/simulation_client Configure client behavior such as disabling console input or logs, setting connection type, IP address, and port. Load `InputCommandRegion` on demand for modularity. ```java public class DemoClient { static void start(long userId) { // US or CHINA Locale.setDefault(Locale.US); ClientUserConfigs.closeScanner = true; ClientUserConfigs.closeLog(); List inputCommandRegions = List.of( new HallRegion() // , new RoomRegion() // , new Jsr380Region() // , new BroadcastRegion() ); new ClientRunOne() .setInputCommandRegions(inputCommandRegions) .idle(10) .setJoinEnum(ExternalJoinEnum.TCP) .setConnectAddress("127.0.0.1") .setConnectPort(ExternalGlobalConfig.externalPort) .startup(); } } ``` -------------------------------- ### Aggregation Process Setup Source: https://iohao.github.io/ionet/en/docs/manual_high/deploy-multi-process This code initializes the `Aeron` runtime, enables the `CenterServer`, and sets up the external service for the aggregation process. It serves as the unified access point for all logic services. ```java public final class OneApplication { static void main() { var aeron = new EmbeddedAeronRuntime().getAeron(); new RunOne() .setAeron(aeron) .enableCenterServer() .setExternalServer( ExternalMapper.builder(ExternalGlobalConfig.externalPort).build() ) .startup(); } } ``` -------------------------------- ### Clone ionet-ai Repository Source: https://iohao.github.io/ionet/en/docs/ionet-ai Clone the ionet-ai repository locally and install MCP runtime dependencies. This is the first step for both Codex CLI and Claude Code CLI installations. ```bash git clone https://github.com/iohao/ionet-ai.git cd ionet-ai uv sync --extra mcp ``` -------------------------------- ### Run JAR with VM Options Source: https://iohao.github.io/ionet/en/docs/faq When executing a JAR file from the command line, prepend these VM options to the java command. This ensures the application has the necessary permissions. ```bash java \ --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ --enable-native-access=ALL-UNNAMED \ -jar target/ionet-quick-demo.jar ``` -------------------------------- ### Run Once Task with Different Delays Source: https://iohao.github.io/ionet/en/docs/kit/task_kit Demonstrates executing tasks once after varying delays using TaskKit.runOnce. Includes examples for 2 seconds, 1 minute, and 500 milliseconds. ```java TaskKit.runOnce(() -> log.info("2 Seconds"), 2, TimeUnit.SECONDS); ``` ```java TaskKit.runOnce(() -> log.info("1 Minute"), 1, TimeUnit.MINUTES); ``` ```java TaskKit.runOnce(() -> log.info("500 delayMilliseconds"), 500, TimeUnit.MILLISECONDS); ``` -------------------------------- ### Usage Example for ErrorCode Assertion Source: https://iohao.github.io/ionet/en/docs/manual_high/code_organization Use `ErrorCode.xxx.assertTrue(condition)` to assert conditions and throw exceptions with associated error codes. This example checks email format validity. ```java @ActionController(EmailCmd.cmd) public class EmailAction { @ActionMethod(EmailCmd.openEmail) private void openEmail(String email) { Pattern pattern = Pattern.compile("[a-zA-Z0-9_-]+@[\\w\\.].[a-z]+(\\.[a-z]+)?"); var checkedResult = pattern.matcher(email).find(); ErrorCode.emailChecked.assertTrue(checkedResult); } } ``` -------------------------------- ### Define an Action Controller and Method in Java Source: https://iohao.github.io/ionet/en/docs/intro This example demonstrates how to define an action controller and an action method using ionet annotations. Ordinary Java methods are treated as actions, simplifying development and avoiding class explosion. ```java @ActionController(1) public class DemoAction { @ActionMethod(1) private UserMessage jackson(LoginVerifyMessage message) { ErrorCode.nameChecked.assertTrue("Jackson".equals(message.jwt)); var userMessage = new UserMessage(); userMessage.name = "hello Jackson"; return userMessage; } } // ErrorCode public enum ErrorCode implements ErrorInformation { /** Name check */ nameChecked(100, "The name must be Jackson"); final int code; final String message; ErrorCode(int code, String message) { this.code = code; this.message = message; } @Override public String getMessage() { return this.message; } @Override public int getCode() { return this.code; } } @ProtobufClass public class LoginVerifyMessage { public String jwt; } @ProtobufClass public class UserMessage { public String name; } ``` -------------------------------- ### Previous Code Example Source: https://iohao.github.io/ionet/en/docs/manual_high/protocol_fragment Illustrates the previous code structure before refactoring, showing the action controller and the separate protocol definition for EquipClothesId. This highlights the redundancy that the solution aims to eliminate. ```java @ActionController(1) public class DemoAction { @ActionMethod(0) public EquipInfo getEquip(EquipClothesId equipClothesId) { int equipId = equipClothesId.id; ... return equipInfo; } } @ProtobufClass public class EquipClothesId { public int id; } ``` -------------------------------- ### Configure and Start Load Testing with PressureClient Source: https://iohao.github.io/ionet/en/docs/extension_module/simulation_client Sets up parameters for load testing, including the number of users, requests per second, and test rounds. It then simulates virtual users to execute the test. ```java public class PressureClient { static int pressureUserSize = 80; static int pressureSecondsRequest = 10; static int pressureRound = 10; static void main() throws InterruptedException { for (int i = 1; i <= pressureUserSize; i++) { long userId = i; TaskKit.executeVirtual(() -> { ClientUser clientUser = new DefaultClientUser(); clientUser.setJwt(String.valueOf(userId)); new ClientRunOne() .setClientUser(clientUser) .setInputCommandRegions(List.of(new PressureRegion())) .startup(); }); } TimeUnit.SECONDS.sleep(1); } } ``` -------------------------------- ### Java Action: Login Verification Source: https://iohao.github.io/ionet/en Demonstrates login verification using both callback and async/await patterns in Java. The callback approach is simpler, while async/await helps avoid callback hell. ```Java public async Task TestLoginVerify() { var loginVerifyMessage = new LoginVerifyMessage {Jwt = "10"}; // code style: callback. Advantages: simple, integrated. // cn: 编码风格:回调。 优点:简洁,一体化。 MyAction.OfLoginVerify(loginVerifyMessage, result => { var userMessage = result.GetValue(); result.Log(userMessage); }); // code style: async await. Advantages: Avoid callback hell. // cn: 编码风格:async await 机制。 优点:可避免回调地狱。 var result = await MyAction.OfAwaitLoginVerify(loginVerifyMessage); var userMessage = result.GetValue(); result.Log(userMessage); } ``` -------------------------------- ### Start Codex CLI with ionet-ai Source: https://iohao.github.io/ionet/en/docs/ionet-ai Execute the generated startup script from your target project root to launch Codex CLI with the ionet-ai MCP service mounted. This script ensures project-specific configuration without affecting global settings. ```bash ./codex-ionet.sh ``` -------------------------------- ### Add Built-in Plugins to LogicServer Source: https://iohao.github.io/ionet/en/docs/manual/plugin_intro Demonstrates how to add several built-in plugins (DebugInOut, StatActionInOut, ThreadMonitorInOut, TimeRangeInOut) to the LogicServer during its initialization. ```java public class MyLogicServer implements LogicServer { @Override public void settingBarSkeletonBuilder(BarSkeletonBuilder builder) { builder.addInOut(new DebugInOut()); builder.addInOut(new StatActionInOut()); builder.addInOut(new ThreadMonitorInOut()); builder.addInOut(new TimeRangeInOut()); } } ``` -------------------------------- ### Request/Void Client Usage (C#) Source: https://iohao.github.io/ionet/en/docs/manual/communication_model Example of a client making a request to an action that does not return data. ```csharp // C# Code public void TestSay() { var name = "Michael Jackson"; MyAction.OfSay(name); } ``` -------------------------------- ### Generate .proto Files via Utility Class Source: https://iohao.github.io/ionet/en/docs/extension_module/jprotobuf Use the GenerateFileKit utility class to generate .proto files by specifying the package names to scan. The default output directory is 'target/proto'. ```java void test1() { GenerateFileKit.generate("com.iohao.example.sdk.logic.data"); } ``` -------------------------------- ### Get FlowContext via FlowContextKeys Source: https://iohao.github.io/ionet/en/docs/manual/flow_context Obtain FlowContext using FlowContextKeys when not declaring it in method parameters. ```java @ActionController(1) public class DemoAction { @ActionMethod(1) public void demo() { var flowContext = FlowContextKeys.getFlowContext(); } } ``` -------------------------------- ### Standard Project Directory Structure Source: https://iohao.github.io/ionet/en/docs/manual_high/code_organization Illustrates a typical project structure with directories for external dependencies, logic modules, application servers, clients, and shared provide modules. ```plaintext ├── external │ ├── pom.xml │ └── src ├── logic │ ├── email-logic │ └── user-logic ├── one-application │ ├── pom.xml │ └── src ├── one-client │ ├── pom.xml │ └── src └── provide ├── common-provide ├── email-provide └── user-provide ``` -------------------------------- ### Build JAR with Maven Source: https://iohao.github.io/ionet/en/docs/quick_zero_demo Use this Maven command to clean the project and package it into a JAR file. The generated JAR will be approximately 15MB. ```bash mvn clean package ``` -------------------------------- ### Recommended Action Controller Style Source: https://iohao.github.io/ionet/en/docs/manual_high/protocol_fragment Demonstrates the recommended style for an Action Controller, including annotations and method signatures for processing lists of objects. ```java @ActionController(3) public class HallAction { @ActionMethod(10) public List acceptList(List animals) { for (Animal animal : animals) { animal.id = animal.id + 10; } return animals; } } ``` -------------------------------- ### Simulated Client Implementation Source: https://iohao.github.io/ionet/en/docs/quick_zero_demo This Java code defines a simulated client that connects to an external server and sets up various simulated requests and broadcast listeners. It uses Ionet's `ClientRunOne` and `AbstractInputCommandRegion` to configure commands and callbacks. ```java public class DemoClient { static void main() { // US or CHINA Locale.setDefault(Locale.CHINA); // closeLog. cn: 关闭模拟请求相关日志 ClientUserConfigs.closeLog(); // Startup Client. cn: 启动模拟客户端 new ClientRunOne() .setInputCommandRegions(List.of(new DemoRegion())) .startup(); } static class DemoRegion extends AbstractInputCommandRegion { static final Logger log = LoggerFactory.getLogger(DemoRegion.class); @Override public void initInputCommand() { // Setting cmd. cn:设置主路由 this.setCmd(DemoCmd.cmd, "TestDemo"); // ---------------- request 1-0 ---------------- ofCommand(DemoCmd.here).setTitle("here").setRequestData(() -> { HelloMessage helloMessage = new HelloMessage(); helloMessage.name = "1"; return helloMessage; }).callback(result -> { HelloMessage value = result.getValue(HelloMessage.class); log.info("{}", value); }); // ---------------- request 1-1 ---------------- ofCommand(DemoCmd.jackson).setTitle("Jackson").setRequestData(() -> { HelloMessage helloMessage = new HelloMessage(); helloMessage.name = "1"; return helloMessage; }).callback(result -> { // We won't get in here because an exception happened. // The logic for action 1-1 requires the name to be "Jackson". // cn: 不会进入到这里,因为发生了异常。 1-1 action 的逻辑要求 name 必须是 Jackson。 HelloMessage value = result.getValue(HelloMessage.class); log.info("{}", value); }); // ---------------- request 1-2 ---------------- ofCommand(DemoCmd.list).setTitle("list").callback(result -> { // We get list data because the server returns a List // cn: 得到 list 数据,因为服务器返回的是 List List list = result.listValue(HelloMessage.class); log.info("{}", list); }); // ---------------- request 1-3 ---------------- ofCommand(DemoCmd.triggerBroadcast).setTitle("triggerBroadcast"); // ---------------- Broadcast Listener. cn: 广播监听 ---------------- ofListen(result -> { HelloMessage value = result.getValue(HelloMessage.class); log.info("{}", value); }, DemoCmd.listenData, "listenData"); ofListen(result -> { List helloMessageList = result.listValue(HelloMessage.class); log.info("{}", helloMessageList); }, DemoCmd.listenList, "listenList"); } } } ``` -------------------------------- ### Get FlowContext via Action Method Parameter Source: https://iohao.github.io/ionet/en/docs/manual/flow_context Define FlowContext in action method parameters for automatic framework recognition. ```java @ActionController(1) public class DemoAction { @ActionMethod(1) public void demo(FlowContext flowContext) { } } ``` -------------------------------- ### Add run-one Dependency to pom.xml Source: https://iohao.github.io/ionet/en/docs/manual/logic_intro Include the `run-one` dependency in your `pom.xml` to get both external and logic servers for quick testing. ```xml com.iohao.net run-one ${ionet.version} ```