浏览代码

优化消息事件处理系统

johnclot69 4 周之前
父节点
当前提交
ab6f1c0e3f

+ 1 - 1
incubator-app/src/main/java/com/incubator/app/App.java

@@ -12,7 +12,7 @@ public class App {
         Game game = new Game();
         game.start();
 
-        // 阻塞 main 线程,保持服务运行(使用 CountDownLatch 更语义化)
+        // 阻塞 main 线程,保持服务运行
         try {
             Thread.currentThread().join();
         } catch (InterruptedException e) {

+ 149 - 0
incubator-core/src/main/java/com/incubator/core/Cmd.java

@@ -0,0 +1,149 @@
+package com.incubator.core;
+
+/**
+ * 网络消息号定义
+ * 规则:
+ * 1. 所有客户端请求以奇数结尾
+ * 2. 所有服务器响应和推送以偶数结尾
+ * 3. 推送消息以9开头
+ */
+public final class Cmd {
+
+    //******* 服务器 → 客户端 ******//  
+    public static int DEFAULT = 0; //默认
+
+    //******* 游戏服 → 中控 ******//
+    public static int S2S_GAME_REG = 5000;                   // 请求 注册中控
+    public static int S2S_GAME_REG_RSP = 6000;			          // 响应 注册中控
+
+    // 系统消息 100001-100100
+    public static int HeartBeatReq = 100001;             // 心跳请求(客户端)
+    public static int HeartBeatRes = 100002;          // 心跳响应(服务器)
+    public static int LoginReq = 100003;              // 登录请求(客户端)
+    public static int LoginRes = 100004;              // 登录响应(服务器)
+    public static int CreateRoomReq = 100007;         // 创建房间请求
+    public static int CreateRoomRes = 100008;         // 创建房间响应
+    public static int JoinRoomReq = 100009;           // 加入房间请求
+    public static int JoinRoomRes = 100010;           // 加入房间响应
+    public static int RoomReadyReq = 100011;          // 玩家进入房间后点击准备请求
+    public static int RoomReadyRes = 100012;          // 玩家进入房间后点击准备响应
+    public static int PlayDisCardsReq = 100013;       // 出牌请求
+    public static int PlayDisCardsRes = 100014;       // 出牌响应
+    public static int OperationReq = 100015;          // 玩家操作动作吃、碰、杠、胡、过请求
+    public static int OperationRes = 100016;          // 玩家操作动作吃、碰、杠、胡、过响应
+    public static int EnterBackCardsReq = 100017;     // 进还贡牌请求
+    public static int EnterBackCardsRes = 100018;     // 进还贡牌响应
+    public static int RoomRuleInfoReq = 100019;       // 房间规则详细信息请求
+    public static int RoomRuleInfoRes = 100020;       // 房间规则详细信息响应
+
+    public static int LeaveRoomReq = 100025;             //玩家离开房间请求
+    public static int LeaveRoomRes = 100026;             //玩家离开房间响应
+
+    // 测试消息 200001-200100
+    public static int NormalMsgReq = 200001;     // 普通消息请求(客户端)
+    public static int NormalMsgRes = 200002;     // 普通消息响应(服务器)
+
+    // 商城消息 200101-200200
+    public static int ShopInfoReq = 200101;      // 获取商城信息请求(客户端)
+    public static int ShopInfoRes = 200102;      // 获取商城信息响应(服务器)
+    public static int ShopBuyReq = 200103;       // 购买物品请求(客户端)
+    public static int ShopBuyRes = 200104;       // 购买物品响应(服务器)
+
+    // 背包消息 200201-200300
+    public static int BagInfoReq = 200201;       // 获取背包信息请求(客户端)
+    public static int BagInfoRes = 200202;       // 获取背包信息响应(服务器)
+    public static int BagUseReq = 200203;        // 使用物品请求(客户端)
+    public static int BagUseRes = 200204;        // 使用物品响应(服务器)
+
+    //个人中心
+    public static int ProfileInfoReq = 200301;    //个人中心信息请求
+    public static int ProfileInfoRes = 200302;    //个人中心信息响应
+    public static int UpdateAvatarUrlReq = 200303; //修改个人头像请求
+    public static int UpdateAvatarUrlRes = 200304; //修改个人头像响应
+    public static int UpdateNickNameReq = 200305; //修改个人昵称请求
+    public static int UpdateNickNameRes = 200306; //修改个人昵称响应
+    public static int UpdateCharacterUrlReq = 200307; //修改个人人物请求
+    public static int UpdateCharacterUrlRes = 200308; //修改个人人物响应
+    public static int UpdatePhoneReq = 200309; //修改个人手机请求
+    public static int UpdatePhoneRes = 200310; //修改个人手机响应
+    public static int SaveAddressReq = 200311; //保存收货地址请求
+    public static int SaveAddressRes = 200312; //保存收货地址响应
+    public static int GetAddressListReq = 200313; //获取地址列表请求
+    public static int GetAddressListRes = 200314; //获取地址列表响应
+    public static int GetOrderListReq = 200315; //获取订单列表请求
+    public static int GetOrderListRes = 200316; //获取订单列表响应
+    public static int GetUserYaoReq = 200317; //获取推广福利响应
+    public static int GetUserYaoRes = 200318; //获取推广福利响应
+
+
+    //排行榜
+    public static int RankInfoReq = 200401;       //排行榜信息请求
+    public static int RankInfoRes = 200402;       //排行榜信息响应
+
+    //好友
+    public static int FriendInfoReq = 200501;     //好友信息请求
+    public static int FriendInfoRes = 200502;     //好友信息响应
+
+    //俱乐部
+    public static int ClubInfoReq = 200601;       //俱乐部集合信息请求
+    public static int ClubInfoRes = 200602;       //俱乐部集合信息响应
+    public static int MyClubReq = 200603;       //我的俱乐部信息响应
+    public static int MyClubRes = 200604;       //我的俱乐部信息响应
+    public static int SetMainClubReq = 200605;    //设置主俱乐部的请求
+    public static int SetMainClubRes = 200606;    //设置主俱乐部的响应
+    public static int QuitClubReq = 200607;    //退出俱乐部的请求
+    public static int QuitClubRes = 200608;    //退出俱乐部的响应
+    public static int CreateClubReq = 200609;    //创建/修改俱乐部请求
+    public static int CreateClubRes = 200610;    //创建/修改俱乐部响应
+    public static int ApplyJoinClubReq = 200611;    //请求加入俱乐部请求
+    public static int ApplyJoinClubRes = 200612;    //请求加入俱乐部响应
+    public static int GetApplyListReq = 200613;    //获取申请列表请求
+    public static int GetApplyListRes = 200614;    //获取申请列表响应
+    public static int AgreeOrRefuseJoinReq = 200615;    //同意/拒绝加入俱乐部请求
+    public static int AgreeOrRefuseJoinRes = 200616;    //同意/拒绝加入俱乐部响应
+    public static int DeleteMemberReq = 200617;    //踢出俱乐部成员请求
+    public static int DeleteMemberRes = 200618;    //踢出俱乐部成员响应
+    public static int DissolveClubReq = 200619;    //解散俱乐部的请求
+    public static int DissolveClubRes = 200620;    //解散俱乐部的响应
+    public static int GetMyClubListReq = 200621;    //获取我的俱乐部列表请求
+    public static int GetMyClubListRes = 200622;    //获取我的俱乐部列表响应
+    public static int CreateClubListReq = 200623;    //获取创建俱乐部列表请求
+    public static int CreateClubListRes = 200624;    //获取创建俱乐部列表响应
+
+    //官方比赛
+    public static int MatchSignUpReq = 200701;     // 赛事报名请求
+    public static int MatchSignUpRes = 200702;     // 赛事报名响应
+    public static int MatchSignupListReq = 200703;  // 获取官方比赛报名名单请求
+    public static int MatchSignupListRes = 200704;  // 获取官方比赛报名名单响应
+    public static int MatchRoomListReq = 200705;  // 获取官方比赛轮次详情请求
+    public static int MatchRoomListRes = 200706;  // 获取官方比赛轮次详情响应
+
+    //个人活动
+    public static int EventInfoReq = 200801;     // 活动信息请求
+    public static int EventInfoRes = 200802;     // 活动信息响应
+
+    //个人消息
+    public static int MessageInfoReq = 200901;     // 个人消息信息请求
+    public static int MessageInfoRes = 200902;     // 个人消息信息响应
+
+
+    // 服务器推送消息 900000-999999 (全部以偶数结尾)
+    public static int PlayerInfoUpdate = 900002;  // 玩家信息数据变更推送
+    public static int PlayerOnline = 900004;      // 玩家上线推送
+    public static int PlayerOffline = 900006;     // 玩家下线推送
+    public static int RoomPlayerJoin = 900008;    // 玩家加入房间推送
+    public static int RoomPlayerLeave = 900010;   // 玩家离开房间推送
+    public static int ReadyStateUpdate = 900012;  // 玩家准备状态数据同步推送
+    public static int GameStateChange = 900014;   // 游戏状态变化推送
+    public static int DrawCard = 900016;          // 麻将摸牌推送
+    public static int OtherPlayCards = 900020;    // 其他玩家出牌通知
+    public static int OtherPlayOperation = 900022;    // 其他玩家操作动作通知
+    public static int DisbandRoom = 900024;       // 解散房间推送
+
+    public static int MatchPreparationStart = 900026; // 赛事准备开始推送
+    public static int MatchOfficialStart = 900028;   // 赛事正式开始推送
+
+    //    ShopUpdate = 900016;        // 商城更新推送
+    public static int BagUpdate = 900018;         // 背包更新推送
+    public static int ErrorRes = 910000;          // 错误响应(服务器)
+}

+ 0 - 5
incubator-core/src/main/java/com/incubator/core/events/EventListener.java

@@ -1,5 +0,0 @@
-package com.incubator.core.events;
-
-public interface EventListener {
-    void handle(WebSocketMessageEvent event);
-}

+ 2 - 2
incubator-core/src/main/java/com/incubator/core/message/MessageHandler.java

@@ -8,7 +8,7 @@ import io.netty.channel.Channel;
  */
 public abstract class MessageHandler {
 
-    public final int cmd;
+    public int cmd;
 
     protected MessageHandler(int cmd) {
         this.cmd = cmd;
@@ -18,5 +18,5 @@ public abstract class MessageHandler {
      * 抽象处理方法
      * @param message 接收到的消息对象
      */
-    public abstract void handle(Channel channel, Message message);
+    public abstract void handle(Channel session, Message message);
 }

+ 12 - 0
incubator-core/src/main/java/com/incubator/core/message/MessageHandlerListener.java

@@ -0,0 +1,12 @@
+package com.incubator.core.message;
+
+public interface MessageHandlerListener {
+
+    /**
+     * 处理传入的事件对象
+     *
+     * @param event 事件对象,可为任意类型
+     */
+    void handle(Object event);
+
+}

+ 98 - 32
incubator-core/src/main/java/com/incubator/core/message/MessageHandlerSystem.java

@@ -2,75 +2,141 @@ package com.incubator.core.message;
 
 import com.artemis.BaseSystem;
 import com.artemis.annotations.Wire;
-import com.incubator.core.events.EventListener;
-import com.incubator.core.events.WebSocketConnectedEvent;
-import com.incubator.core.events.WebSocketDisconnectedEvent;
-import com.incubator.core.events.WebSocketMessageEvent;
+import com.incubator.core.message.events.WebSocketConnectedEvent;
+import com.incubator.core.message.events.WebSocketDisconnectedEvent;
+import com.incubator.core.message.events.WebSocketMessageEvent;
 import com.incubator.core.protocol.Message;
+import io.netty.channel.Channel;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
- * 消息事件处理系统
+ * 消息处理系统
  * 职责:
- * 1. 管理消息处理器注册
- * 2. 监听并处理网络消息事件
- * 3. 路由消息到对应的处理器
+ * 1. 注册和管理消息处理器(根据消息 cmd 路由)
+ * 2. 作为事件分发器,注册事件监听器并分发 WebSocket 相关事件
+ * 3. 优化高并发场景下的事件分发和消息处理性能
  */
 @Wire
-public class MessageHandlerSystem extends BaseSystem implements EventListener {
-    // key:cmd value:handler处理器
-    private final Map<Integer, MessageHandler> handlers = new HashMap<>();
+public class MessageHandlerSystem extends BaseSystem implements MessageHandlerListener {
+
+    // 使用线程安全的数据结构保存消息处理器,key 为消息 cmd
+    private final ConcurrentHashMap<Integer, MessageHandler> handlers = new ConcurrentHashMap<>();
+    // 事件监听器集合:key 为事件类型,value 为该类型下所有的监听器
+    private final ConcurrentHashMap<Class<?>, CopyOnWriteArrayList<MessageHandlerListener>> listeners = new ConcurrentHashMap<>();
 
     @Override
     protected void initialize() {
-        // websocket事件分发器(由Artemis自动注入)
-        WebSocketEventDispatcherSystem eventDispatcher = this.world.getSystem(WebSocketEventDispatcherSystem.class);
-        // 注册事件监听器
-        eventDispatcher.addListener(this, WebSocketConnectedEvent.class);
-        eventDispatcher.addListener(this, WebSocketMessageEvent.class);
-        eventDispatcher.addListener(this, WebSocketDisconnectedEvent.class);
+        // 注册自身作为 WebSocket 相关事件的监听器
+        addListener(this, WebSocketConnectedEvent.class);
+        addListener(this, WebSocketMessageEvent.class);
+        addListener(this, WebSocketDisconnectedEvent.class);
 
-        // 示例注册(实际项目中应使用自动扫描或手动注册)
+        // 示例注册(实际项目中可通过自动扫描或配置注册)
         // registerHandler(new LoginHandler());
     }
 
     /**
      * 注册消息处理器
-     * @param handler 消息处理器实例
+     * @param handler 消息处理器实例,handler.cmd 作为消息标识
      */
     public void registerHandler(MessageHandler handler) {
-        if (handlers.containsKey(handler.cmd)) {
+        MessageHandler prev = handlers.putIfAbsent(handler.cmd, handler);
+        if (prev != null) {
             throw new IllegalArgumentException("Handler for cmd " + handler.cmd + " already exists");
         }
-        handlers.put(handler.cmd, handler);
     }
 
     /**
-     * 处理WebSocket消息事件
-     * @param event 包含消息内容的事件对象
+     * 添加事件监听器到指定的事件类型
+     * @param listener 监听器实例
+     * @param eventType 事件类型 Class 对象
+     */
+    public <T> void addListener(MessageHandlerListener listener, Class<T> eventType) {
+        listeners.computeIfAbsent(eventType, key -> new CopyOnWriteArrayList<>()).add(listener);
+    }
+
+    /**
+     * 分发事件。直接根据事件类型判断调用对应的处理方法,避免反射调用,提高性能。
+     * @param event 事件实例
+     */
+    public void dispatch(Object event) {
+        if (event instanceof WebSocketMessageEvent) {
+            // 直接交给自身处理消息事件
+            handle((WebSocketMessageEvent) event);
+        } else if (event instanceof WebSocketConnectedEvent) {
+            handle((WebSocketConnectedEvent) event);
+        } else if (event instanceof WebSocketDisconnectedEvent) {
+            handle((WebSocketDisconnectedEvent) event);
+        }
+        // 同时通知注册的其他监听器(如果有扩展需求)
+        CopyOnWriteArrayList<MessageHandlerListener> list = listeners.get(event.getClass());
+        if (list != null) {
+            for (MessageHandlerListener listener : list) {
+                // 避免重复处理自己已经处理的事件
+                if (listener != this) {
+                    listener.handle(event);
+                }
+            }
+        }
+    }
+
+    /**
+     * 处理 WebSocket 消息事件:根据消息的 cmd 路由到对应的消息处理器进行处理
+     * @param event WebSocketMessageEvent 实例
      */
     public void handle(WebSocketMessageEvent event) {
         Message message = event.message();
         MessageHandler handler = handlers.get(message.cmd);
-
         if (handler != null) {
             try {
                 handler.handle(event.channel(), message);
             } catch (Exception e) {
-                System.err.printf("Error processing cmd=%d: %s%n",
-                        message.cmd, e);
+                System.err.printf("Error processing cmd=%d: %s%n", message.cmd, e.getMessage());
             }
         } else {
-            // 处理未注册命令的情况
-            System.err.printf("No handler found for cmd=%d | type=%s%n",
-                    message.cmd, message.getClass().getSimpleName());
+            System.err.printf("No handler found for cmd=%d | type=%s%n", message.cmd, message.getClass().getSimpleName());
+        }
+    }
+
+    /**
+     * 处理 WebSocket 连接建立事件
+     * @param event WebSocketConnectedEvent 实例
+     */
+    public void handle(WebSocketConnectedEvent event) {
+        Channel channel = event.channel();
+        System.out.println("Channel connected: " + channel);
+        // 此处可扩展注册该连接的相关逻辑,如存储在线状态等
+    }
+
+    /**
+     * 处理 WebSocket 连接关闭事件
+     * @param event WebSocketDisconnectedEvent 实例
+     */
+    public void handle(WebSocketDisconnectedEvent event) {
+        Channel channel = event.channel();
+        System.out.println("Channel disconnected: " + channel);
+        // 此处可扩展移除连接记录等操作
+    }
+
+    /**
+     * 泛型处理方法,当作为事件监听器调用时,根据事件类型分发到具体的处理方法
+     * @param event 事件对象
+     */
+    @Override
+    public void handle(Object event) {
+        if (event instanceof WebSocketMessageEvent) {
+            handle((WebSocketMessageEvent) event);
+        } else if (event instanceof WebSocketConnectedEvent) {
+            handle((WebSocketConnectedEvent) event);
+        } else if (event instanceof WebSocketDisconnectedEvent) {
+            handle((WebSocketDisconnectedEvent) event);
         }
     }
 
     @Override
     protected void processSystem() {
-        // 由事件驱动处理,无需每帧执行
+        // 事件驱动,不需要每帧处理逻辑
     }
 }

+ 0 - 57
incubator-core/src/main/java/com/incubator/core/message/WebSocketEventDispatcherSystem.java

@@ -1,57 +0,0 @@
-package com.incubator.core.message;
-
-import com.artemis.BaseSystem;
-
-import com.artemis.utils.reflect.ClassReflection;
-import com.artemis.utils.reflect.ReflectionException;
-import com.incubator.core.events.EventListener;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * 自定义事件分发系统(需注册到Artemis世界)
- */
-public class WebSocketEventDispatcherSystem extends BaseSystem {
-
-    private final Map<Class<?>, List<EventListener>> listeners = new HashMap<>();
-
-    /**
-     * 添加事件监听器
-     * @param eventType 事件类型类对象
-     * @param listener 监听器实现
-     */
-    public <T> void addListener(Object listener, Class<T> eventType) {
-        if (!listeners.containsKey(eventType)) {
-            listeners.put(eventType, new ArrayList<>());
-        }
-        listeners.get(eventType).add((EventListener) listener);
-    }
-
-    /**
-     * 分发事件到所有监听器
-     * @param event 事件实例
-     */
-    public void dispatch(Object event) {
-        Class<?> eventType = event.getClass();
-        if (listeners.containsKey(eventType)) {
-            for (EventListener listener : listeners.get(eventType)) {
-                try {
-                    ClassReflection.getMethod(listener.getClass(), "handle", eventType)
-                            .invoke(listener, event);
-                } catch (ReflectionException e) {
-                    System.err.println("Error dispatching event: " + e.getMessage());
-                }
-            }
-        }
-    }
-
-    @Override
-    protected void processSystem() {
-        // 事件系统通过dispatch方法触发,无需每帧处理
-    }
-
-}

+ 1 - 1
incubator-core/src/main/java/com/incubator/core/events/WebSocketConnectedEvent.java → incubator-core/src/main/java/com/incubator/core/message/events/WebSocketConnectedEvent.java

@@ -1,4 +1,4 @@
-package com.incubator.core.events;
+package com.incubator.core.message.events;
 
 import io.netty.channel.Channel;
 

+ 1 - 1
incubator-core/src/main/java/com/incubator/core/events/WebSocketDisconnectedEvent.java → incubator-core/src/main/java/com/incubator/core/message/events/WebSocketDisconnectedEvent.java

@@ -1,4 +1,4 @@
-package com.incubator.core.events;
+package com.incubator.core.message.events;
 
 import io.netty.channel.Channel;
 

+ 1 - 1
incubator-core/src/main/java/com/incubator/core/events/WebSocketMessageEvent.java → incubator-core/src/main/java/com/incubator/core/message/events/WebSocketMessageEvent.java

@@ -1,4 +1,4 @@
-package com.incubator.core.events;
+package com.incubator.core.message.events;
 
 import io.netty.channel.Channel;
 import com.incubator.core.protocol.Message;

+ 9 - 9
incubator-core/src/main/java/com/incubator/core/network/WebSocketHandler.java

@@ -1,35 +1,35 @@
 package com.incubator.core.network;
 
 import com.artemis.World;
-import com.incubator.core.events.WebSocketConnectedEvent;
-import com.incubator.core.events.WebSocketDisconnectedEvent;
-import com.incubator.core.events.WebSocketMessageEvent;
+import com.incubator.core.message.events.WebSocketConnectedEvent;
+import com.incubator.core.message.events.WebSocketDisconnectedEvent;
+import com.incubator.core.message.events.WebSocketMessageEvent;
+import com.incubator.core.message.MessageHandlerSystem;
 import io.netty.channel.Channel;
-import com.incubator.core.message.WebSocketEventDispatcherSystem;
 import com.incubator.core.protocol.Message;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
 
 public class WebSocketHandler extends SimpleChannelInboundHandler<Message> {
 
-    private final WebSocketEventDispatcherSystem eventDispatcher;
+    private final MessageHandlerSystem messageHandlerSystem;
 
     public WebSocketHandler(World world) {
-        this.eventDispatcher = world.getSystem(WebSocketEventDispatcherSystem.class);
+        this.messageHandlerSystem = world.getSystem(MessageHandlerSystem.class);
     }
 
     @Override
     public void channelActive(ChannelHandlerContext ctx) {
         System.out.println("WebSocket channel active: " + ctx.channel());
         // 触发连接建立事件
-        this.eventDispatcher.dispatch(new WebSocketConnectedEvent(ctx.channel()));
+        this.messageHandlerSystem.dispatch(new WebSocketConnectedEvent(ctx.channel()));
     }
 
     @Override
     protected void channelRead0(ChannelHandlerContext ctx, Message msg) {
         System.out.println("Received message: " + msg);
         // 通过Artemis事件系统分发携带完整消息对象的事件
-        this.eventDispatcher.dispatch(new WebSocketMessageEvent(ctx.channel(), msg));
+        this.messageHandlerSystem.dispatch(new WebSocketMessageEvent(ctx.channel(), msg));
     }
 
     @Override
@@ -37,7 +37,7 @@ public class WebSocketHandler extends SimpleChannelInboundHandler<Message> {
         Channel channel = ctx.channel();
         System.out.println("WebSocket channel inactive: " + channel);
         // 触发连接关闭事件
-        this.eventDispatcher.dispatch(new WebSocketDisconnectedEvent(channel));
+        this.messageHandlerSystem.dispatch(new WebSocketDisconnectedEvent(channel));
         super.channelInactive(ctx);
     }
 

+ 165 - 0
incubator-core/src/main/java/com/incubator/core/protocol/Message.java

@@ -1,6 +1,7 @@
 package com.incubator.core.protocol;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -27,6 +28,170 @@ public class Message implements Serializable {
         this.data = data;
     }
 
+    /**
+     * 根据 key 获取 data 字段的值,返回默认值如果不存在或类型不匹配
+     *
+     * @param key   要获取的 key
+     * @param clazz 期望的返回值类型的 Class 对象
+     * @param defaultValue 默认值
+     * @param <T>   泛型,用于指定返回值类型
+     * @return 返回 key 对应的值,如果不存在或类型不匹配则返回 defaultValue
+     */
+    public <T> T getDataValue(String key, Class<T> clazz, T defaultValue) {
+        try {
+            return this.getDataValue(key, clazz) != null ? clazz.cast(this.getDataValue(key, clazz)) : defaultValue;
+        } catch (IllegalArgumentException e) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 根据 key 获取 data 字段的值,并确保类型匹配
+     *
+     * @param key   要获取的 key
+     * @param clazz 期望的返回值类型的 Class 对象
+     * @param <T>   泛型,用于指定返回值类型
+     * @return 返回 key 对应的值,如果不存在或类型不匹配则返回 null
+     * @throws IllegalArgumentException 如果类型不匹配
+     */
+    private <T> T getDataValue(String key, Class<T> clazz) {
+        if (key == null || clazz == null) {
+            throw new IllegalArgumentException("Key and clazz cannot be null");
+        }
+
+        Object value = this.data.get(key);
+
+        // 如果值为 null,直接返回 null
+        if (value == null) {
+            return null;
+        }
+
+        // 处理基本数据类型 (int, long, double, float, boolean, char)
+        if (isBasicType(clazz)) {
+            return handleBasicType(value, clazz);
+        }
+
+        // 处理数组类型(包括 int[], Integer[], String[] 等)
+        if (clazz.isArray()) {
+            return handleArrayType(value, clazz);
+        }
+
+        // 处理集合类型 (ArrayList)
+        if (clazz == ArrayList.class && value instanceof ArrayList) {
+            return clazz.cast(value);
+        }
+
+        // 处理 Map 类型
+        if (clazz == Map.class && value instanceof Map) {
+            return clazz.cast(value);
+        }
+
+        // 如果类型匹配,直接返回
+        if (clazz.isInstance(value)) {
+            return clazz.cast(value);
+        }
+
+        // 类型不匹配,抛出异常
+        throw new IllegalArgumentException(
+                String.format("Value for key '%s' is not of type %s, but of type %s",
+                        key, clazz.getName(), value.getClass().getName()));
+    }
+
+    /**
+     * 判断是否为基本类型
+     */
+    private boolean isBasicType(Class<?> clazz) {
+        return clazz == Integer.class || clazz == int.class ||
+                clazz == Long.class || clazz == long.class ||
+                clazz == Double.class || clazz == double.class ||
+                clazz == Float.class || clazz == float.class ||
+                clazz == Boolean.class || clazz == boolean.class ||
+                clazz == Character.class || clazz == char.class ||
+                clazz == String.class;
+    }
+
+    /**
+     * 处理基本数据类型 (Integer, Long, Double, Float, Boolean, Character)
+     */
+    private <T> T handleBasicType(Object value, Class<T> clazz) {
+        // 处理数值类型 (Integer, Long, Double, Float)
+        if (value instanceof Number numberValue) {
+
+            if (clazz == Integer.class || clazz == int.class) {
+                return clazz.cast(numberValue.intValue());
+            } else if (clazz == Long.class || clazz == long.class) {
+                return clazz.cast(numberValue.longValue());
+            } else if (clazz == Double.class || clazz == double.class) {
+                return clazz.cast(numberValue.doubleValue());
+            } else if (clazz == Float.class || clazz == float.class) {
+                return clazz.cast(numberValue.floatValue());
+            }
+        }
+
+        // 处理 Boolean 类型
+        if (clazz == Boolean.class || clazz == boolean.class) {
+            if (value instanceof Boolean) {
+                return clazz.cast(value);
+            } else if (value instanceof Number) {
+                return clazz.cast(((Number) value).intValue() != 0);
+            } else if (value instanceof String) {
+                return clazz.cast(Boolean.parseBoolean((String) value));
+            }
+        }
+
+        // 处理 Character 类型
+        if (clazz == Character.class || clazz == char.class) {
+            if (value instanceof String && ((String) value).length() == 1) {
+                return clazz.cast(((String) value).charAt(0));
+            }
+        }
+
+        // 处理 String 类型
+        if (clazz == String.class) {
+            // 如果值已经是 String,直接返回
+            if (value instanceof String) {
+                return clazz.cast(value);
+            }
+
+            // 否则尝试将其他类型转换为 String
+            return clazz.cast(value.toString());
+        }
+
+        return null;
+    }
+
+    /**
+     * 处理数组类型 (int[], Integer[], String[], etc.)
+     */
+    private <T> T handleArrayType(Object value, Class<T> clazz) {
+        if (value instanceof ArrayList<?> list) {
+
+            // 处理 int[] 和 Integer[]
+            if (clazz == int[].class) {
+                return clazz.cast(list.stream().mapToInt(item -> ((Number) item).intValue()).toArray());
+            } else if (clazz == Integer[].class) {
+                return clazz.cast(list.stream().map(item -> ((Number) item).intValue()).toArray(Integer[]::new));
+            } else if (clazz == String[].class) {
+                return clazz.cast(list.toArray(new Object[0]));
+            } else if (clazz == Double[].class) {
+                return clazz.cast(list.stream().map(item -> ((Number) item).doubleValue()).toArray(Double[]::new));
+            } else if (clazz == long[].class) {
+                return clazz.cast(list.stream().mapToLong(item -> ((Number) item).longValue()).toArray());
+            } else if (clazz == Long[].class) {
+                return clazz.cast(list.stream().map(item -> ((Number) item).longValue()).toArray(Long[]::new));
+            } else if (clazz == Float[].class) {
+                return clazz.cast(list.stream().map(item -> ((Number) item).floatValue()).toArray(Float[]::new));
+            }
+        }
+
+        // 处理原生数组
+        if (value.getClass().isArray()) {
+            return clazz.cast(value);
+        }
+
+        return null;
+    }
+
     @Override
     public String toString() {
         return "Message : {cmd=" + cmd + ", code=" + code + ", message='" + message + "', data=" + data + "}";

+ 18 - 6
incubator-game/src/main/java/com/incubator/game/Game.java

@@ -4,9 +4,11 @@ import com.artemis.Entity;
 import com.artemis.World;
 import com.artemis.WorldConfiguration;
 import com.artemis.WorldConfigurationBuilder;
+import com.incubator.core.Cmd;
+import com.incubator.core.message.MessageHandler;
 import com.incubator.core.message.MessageHandlerSystem;
-import com.incubator.core.message.WebSocketEventDispatcherSystem;
 import com.incubator.core.network.NettySystem;
+import com.incubator.game.handler.LoginHandler;
 
 import java.time.Duration;
 import java.util.concurrent.Executors;
@@ -24,15 +26,20 @@ public class Game {
     private ScheduledExecutorService executor;
 
     public Game() {
-        // 构建 WorldConfiguration,注册 RealmSystem 和 GameSystem
+        // 构建 WorldConfiguration,注册 GameSystem
         WorldConfiguration config = new WorldConfigurationBuilder()
-                .with(new WebSocketEventDispatcherSystem())
                 .with(new MessageHandlerSystem())
                 .with(new NettySystem())
                 .build();
 
         // 创建 World 对象(服务端主实体)
         this.world = new World(config);
+
+        // 初始化协议
+        MessageHandlerSystem messageHandlerSystem = this.world.getSystem(MessageHandlerSystem.class);
+        if (messageHandlerSystem != null) {
+            messageHandlerSystem.registerHandler(new LoginHandler(Cmd.LoginReq));
+        }
     }
 
     /**
@@ -54,10 +61,15 @@ public class Game {
         // 添加 JVM 关闭钩子,确保退出时释放资源
         Runtime.getRuntime().addShutdownHook(new Thread(() -> {
             System.out.println("Shutdown hook triggered, releasing resources...");
-            this.world.dispose();
-            this.executor.shutdown();
+            this.shutdown();
         }));
-
     }
 
+    /**
+     * 服务关闭时调用,释放 ScheduledExecutorService 和 World 资源
+     */
+    public void shutdown() {
+        this.world.dispose();
+        this.executor.shutdown();
+    }
 }

+ 23 - 0
incubator-game/src/main/java/com/incubator/game/handler/LoginHandler.java

@@ -0,0 +1,23 @@
+package com.incubator.game.handler;
+
+import com.incubator.core.message.MessageHandler;
+import com.incubator.core.protocol.Message;
+import io.netty.channel.Channel;
+
+/**
+ * 登录请求
+ */
+public class LoginHandler extends MessageHandler {
+
+    public LoginHandler(int cmd) {
+        super(cmd);
+    }
+
+    @Override
+    public void handle(Channel session, Message message) {
+        String username = message.getDataValue("username", String.class, "");
+        String password = message.getDataValue("password", String.class, "");
+
+        session.writeAndFlush(new Message());
+    }
+}