kyll3r/GunBound-Java-Server

GitHub: kyll3r/GunBound-Java-Server

基于 Java 21 与 Netty 构建的 GunBound Thor's Hammer 完整服务器模拟器,用于复刻并延续这款经典多人在线游戏的服务端体验。

Stars: 3 | Forks: 6

# GunBound Java Emulator - Thor's Hammer(服务器模拟器) 这是一个经典多人在线游戏 **GunBound** 的服务器模拟器,专门针对带有 **_Ex-Item_** 和 **_Power User_** 支持的 **Thor's Hammer 版本(GIS v376 / GBS v404)**。它使用 Java 构建,利用高性能的 **Netty** 网络框架来处理与游戏客户端的异步、事件驱动的 socket 通信。 ## 🏗️ 系统架构与网络流 该模拟器分为三个独立的服务器 daemon 协同工作,以管理玩家会话: ``` graph TD Client[GunBound Client] -->|TCP 8372| Broker[Broker Server] Client -->|TCP 8360| GameServer[Game Server] Client -->|TCP 8352| BuddyServer[Buddy Server] Broker -.->|Returns channel list| Client GameServer -->|Persists data| DB[(MariaDB / MySQL)] BuddyServer -->|Friends & Messages| DB ``` 1. **Broker 服务器(GunBoundBrokerServer - 默认端口:8372)**: * 客户端的初始连接点。 * 处理命令 `0x1013`(Broker 身份验证请求)和 `0x1100`(服务器目录请求)。 * 返回动态的活动 Game Server 列表(`0x1102`),详细说明名称、描述、IP 地址、端口和实时利用率。 2. **Game 服务器(GunBoundGameServer - 默认端口:8360)**: * 管理频道、大厅和游戏房间的主要游戏 daemon。 * 处理用户身份验证、频道聊天、大厅同步、房间生命周期、地图选择、坦克(mobile)选择验证、Avatar Shop 交易以及实时游戏对局。 3. **Buddy 服务器(GunBoundBuddyServer - 默认端口:TCP 8352)**: * 负责管理好友列表、即时消息、活动状态跟踪(在线/离线)以及游戏内部邮件系统(Buddy Mail)。 ## 🧠 设计模式与技术决策 该模拟器被设计为具有高度可扩展性、线程安全和模块化。使用的关键架构和设计模式包括: ### 1. 响应式与非阻塞网络(Netty Pipeline) * **事件驱动架构**:使用 Netty 的 `ChannelPipeline` 异步处理网络 I/O。 * **数据包分帧(解码)**:在 `PacketDecoder` 中实现,它拦截 TCP 流并缓冲传入数据,直到接收到完整的 payload 大小(以小端序 short 指定在前 2 个字节中),然后再将其分发给下游 handler。 * **空闲状态检测**:pipeline 中的 `IdleStateHandler` 监控通道不活动情况(例如,缺少 keep-alive 数据包)并优雅地关闭非活动 socket,防止资源泄漏和僵尸会话。 ### 2. 现代并发模型 * **Java 21 虚拟线程**:`GunBoundStarter` 使用 `Executors.newVirtualThreadPerTaskExecutor()` 启动服务器实例。这允许服务器在轻量级虚拟线程上运行,从而大幅减少操作系统线程开销。 * **序列化房间操作队列**: 为了防止在共享游戏房间状态上发生竞态条件(例如并发 HP 更新、准备/取消准备状态更改或玩家操作),同时避免阻塞主事件循环或产生繁重的同步锁,每个 `GameRoom` 都运行一个 **类似 Actor 的消息队列**: - 操作被封装到 `Runnable` 任务中。 - 任务通过 `submitAction(Runnable, ChannelHandlerContext)` 提交到房间的任务队列。 - 由 `AtomicBoolean`(`processing`)管理的线程安全循环确保每次仅从队列中执行一个任务,并在客户端各自的 Netty `EventLoop` 线程上运行。 * **线程安全数据结构**:利用 `ConcurrentHashMap` 来包含玩家会话和游戏状态的映射,并使用 `PriorityBlockingQueue` 来跟踪和重用空闲的房间插槽(确保新玩家始终被分配到 0 到 7 之间最低的可用插槽 ID)。 ### 3. 数据包处理中的关注点分离 * **Opcode 分发注册表(工厂模式)**: `OpcodeReaderFactory` 将数字命令 opcode 映射到功能执行块(`BiConsumer`)。这种解耦的路由注册表取代了庞大的条件块(`if/else` 阶梯),并促进了简洁的协议扩展。 * **解耦的读取器与写入器**: - **读取器**:`packets.readers` 下的类提取并解析原始二进制结构(`ByteBuf`),验证参数,并将业务操作委托给服务或房间控制器。 - **写入器**:`packets.writers` 下的类纯粹负责将 Java 对象和游戏状态序列化回 GunBound 客户端预期的符合协议的字节结构。 ### 4. 持久化与数据访问架构(DAO 与服务) * **HikariCP 连接池**:在 `DatabaseManager` 中配置了生产级参数(2 分钟 keep-alive ping,`ConnectionTestQuery` 设置为 `SELECT 1`,以及 30 分钟的最大连接生命周期),以消除驱动程序级别的超时和“连接已关闭”错误。 * **DAO 模式(数据访问对象)**: - 持久化操作在接口类中声明(例如 `UserDAO`、`ChestDAO`、`StatsDAO`)。 - 原始 SQL 查询生成和事务更新隔离在 JDBC 实现类内部(例如 `UserJDBC`、`ChestJDBC`)。 - 实例化和依赖注入通过集中的 `DAOFactory` 进行管理。 * **服务层模式**: 类(例如 `UserServiceImpl` 和 `ShopServiceImpl`)将控制器和读取器与直接的数据库驱动程序解耦,封装了游戏规则(例如,验证购买条件,计算金币和 GP 更新)。 ## 🔐 GunBound 协议加密 该模拟器的一个关键组件是处理 GunBound 的自定义二进制安全层: ### 静态加密 在初始握手、Broker 通信和登录阶段使用。它在 ECB 模式下使用带有硬编码静态密钥的 AES-128(`AES/ECB/NoPadding`): `FF B3 B3 BE AE 97 AD 83 B9 61 0E 23 A4 3C 2E B0` ### 动态加密 用户通过身份验证后,客户端和服务器将过渡到动态加密: 1. **密钥派生**:服务器通过将玩家的 `username`、`password` 与身份验证期间生成的随机 16 字节 `authToken` 进行拼接,为每个会话派生唯一的 128 位密钥。 2. **自定义 SHA-0 变体**:使用 **SHA-0** 散列算法的自定义实现对该拼接字符串进行散列处理。 3. **截断与端序交换**:将生成的 20 字节散列值截断为 16 字节。然后以 4 字节块交换这些字节(小端字旋转),形成最终的 AES-128 密钥。 4. **命令校验和**: - 传出的动态 payload 必须对齐到 12 字节边界。 - 对于每 12 字节的 payload 块,服务器会前置一个 4 字节的命令校验和,计算方式为 `0x8631607E + COMMAND_OPCODE`。 - 然后,最终的 16 字节块将使用派生的动态 AES 密钥进行加密。收到后,服务器会解密 payload,验证命令校验和,并将其丢弃以提取原始的 12 字节段。 ### 序列验证(LCG) 为了防止数据包重放攻击,GunBound 协议在 6 字节的头部内使用序列校验和,该校验和使用线性同余生成器(LCG)根据发送的总字节数(`sumPacketLength`)动态计算: $$\text{Sequence} = (((\text{sumPacketLength} \times \text{0x43FD}) \ \& \ \text{0xFFFF}) - \text{0x53FD}) \ \& \ \text{0xFFFF}$$ *初始握手数据包使用固定的种子值 `0xCBEB`。* ## 📁 项目目录结构 ``` src/main/java/br/com/gunbound/emulator │ ├── GunBoundStarter.java # Main server bootstrapper (spawns Broker, Game, and Buddy servers) ├── ServerConfig.java # Singleton configuration loader for config.properties ├── ConnectionManager.java # Core registry managing active Netty channels │ ├── broker/ # Directory/Router Server (Broker) │ ├── GunBoundBrokerServer.java │ └── GunBoundBrokerServerHandler.java │ ├── buddy/ # Social & Friend List Server (Buddy) │ ├── GunBoundBuddyServer.java │ ├── GunBundBuddyServerHandler.java │ ├── config/ # Buddy decoders and logging handlers │ ├── db/ │ ├── entities/ │ └── packet/ # Buddy packet readers and writers │ ├── db/ # Database Manager & HikariCP Pool Configuration │ ├── DatabaseManager.java # Configures HikariCP datasources │ └── DB.java │ ├── gameserver/ # Core Game Logic Server │ ├── GunBoundGameServer.java │ ├── handlers/ # Netty pipeline handlers for game server sockets │ ├── lobby/ # Channel, Lobby and chat coordination │ ├── playdata/ # Game assets metadata (maps, spawn points) │ ├── packets/ # Protocol routing, opcodes, and factory definitions │ │ ├── OpcodeReaderFactory.java # Opcode command router registry │ │ ├── readers/ # Message payload decoders (Login, Chat, Shop, Room settings) │ │ └── writers/ # Binary response packet builders │ └── room/ # Match room logic │ ├── GameRoom.java # Room state controller & room-bound action queue │ ├── RoomManager.java # Singleton managing room allocations │ └── onlymob/ # Restrictive mode implementations (e.g. Only Mob Commands) │ ├── model/ # Data Entities & Persistence Layer (DAOs) │ ├── entities/ # Data transfer objects (User, Avatar, Chest, ServerOption) │ └── DAO/ # Data Access interfaces & JDBC implementations (impl) │ ├── services/ # Business Logic Services (Shop, Users, Auth) │ └── impl/ # Service implementation layers │ └── utils/ # Utilities & Cryptographic helpers ├── crypto/ │ └── GunBoundCipher.java # Static/Dynamic cipher algorithms & SHA-0 implementation ├── PacketDecoder.java # Netty ByteToMessageDecoder for packet sizes └── PacketUtils.java # LCG Sequence generators, packet header assemblers ``` ## 🛠️ 前置条件 要构建和运行此模拟器,请确保您的开发环境具备: * **Java Development Kit (JDK) 21** 或更高版本(虚拟线程功能必需)。 * **Apache Maven 3.8** 或更高版本。 * **MariaDB 10.4+**(或 MySQL 8.0+)。 * GunBound 客户端文件(Thor's Hammer 版本,GIS v376 或 GBS v404)。 ## ⚙️ 环境设置 ### 1. 数据库设置 1. 在您的数据库服务器中创建一个新的数据库 schema(例如 `gbth`)。 2. 导入所需的 SQL schema 表(`user`、`game`、`chest`、`menu` 等)。 ### 2. 配置属性 在项目的根目录下创建一个名为 `config/` 的文件夹,并在其中创建一个名为 `config.properties` 的文件。 配置以下必填项: ``` # =============================================== # GENERAL SERVER CONFIGURATIONS # =============================================== # Public IP of the server where the emulator will run. # Use 127.0.0.1 for local testing. server.public.ip=127.0.0.1 # =============================================== # BROKER SERVER CONFIGURATIONS # =============================================== # Port that the Broker Server will use to accept initial connections. broker.port=8372 broker.serv1.name=GunBound Legacy broker.serv1.descr=Avatar OFF # =============================================== # GAME SERVER CONFIGURATIONS # =============================================== # Port that the main Game Server will use. gameserver.port=8360 # Probability of getting Dragon/Knight (hidden tanks) gameserver.tank.hidden.ratio=10 gameserver.goldfactor=100 gameserver.scorefactor=100 gameserver.stage0_probability=5 # Event settings gameserver.eventtrigger=1 gameserver.eventactprop=50 # Honk (megaphone) price gameserver.honkprice=10000 # Balloon (chat bubble) price gameserver.balloonprice=50000 # Talk text color price gameserver.colorprice=50000 # PowerUser settings gameserver.superuseritem=204801 gameserver.channelment=#GunBound Legacy Thor's Hammer gameserver.channeldaymsg=*Bom Dia gameserver.channelafternoonmsg=*Boa Tarde gameserver.channelnightmsg=*Boa Noite gameserver.roomment=&Jogue Limpo! gameserver.versionfirst=100 gameserver.versionlast=900 gameserver.passableauthority=0 gameserver.funcrestrict=1040384 # =============================================== # BUDDY SERVER CONFIGURATIONS # =============================================== # TCP Port that the Buddy Server (friends system) will use. buddy.port=8352 # UDP Port for the Buddy Server chat/presence service. buddy.udp.port=8381 # Database Credentials db.url=jdbc:mariadb://localhost:3306/gbth db.user=your_db_username db.password=your_db_password db.useSSL=false ``` ## 🚀 运行模拟器 1. 在仓库的根目录中打开您的终端。 2. 使用 Maven 编译应用程序并下载依赖项: mvn clean install 3. 通过引导类运行编译后的应用程序: mvn exec:java -Dexec.mainClass="br.com.gunbound.emulator.GunBoundStarter" 4. 如果配置正确,启动日志将输出 HikariCP 连接池初始化的信息,随后会显示 Broker、Game 和 Buddy 服务器正在其各自端口上监听的确认消息。 ### 截图 ![游戏房间](https://static.pigsec.cn/wp-content/uploads/repos/cas/66/66cfc347b92ede6a644c6c40db905cf2c2150e1c1074b469576148444978adf4.jpg) ![游戏对局](https://static.pigsec.cn/wp-content/uploads/repos/cas/21/21fbcdcb10fc38406e81e8972efdd8d6873f8cfd41019009949c66a3fada8c11.png) ![Avatar Shop](https://static.pigsec.cn/wp-content/uploads/repos/cas/9f/9f5b8914bf18867608ef44035b51e98d2053d011780b4f0ac02a69288ce578f4.jpg) 对我们中的许多人来说,GunBound 不仅仅是一款游戏,它是我们童年的一部分,是一个创造了难忘回忆的社区。 我希望有一天 Softnyx 能将 GunBound 的未来托付给对的人,让它的辉煌岁月再次闪耀。 ## 📜 许可证与免责声明 本项目基于 **MIT License** 授权。有关许可证文本,请参阅 [LICENSE.txt](LICENSE.txt)。
标签:GunBound, Netty, 域名枚举, 多人在线游戏, 服务端模拟器, 游戏服务器