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 服务器正在其各自端口上监听的确认消息。
### 截图



对我们中的许多人来说,GunBound 不仅仅是一款游戏,它是我们童年的一部分,是一个创造了难忘回忆的社区。
我希望有一天 Softnyx 能将 GunBound 的未来托付给对的人,让它的辉煌岁月再次闪耀。
## 📜 许可证与免责声明
本项目基于 **MIT License** 授权。有关许可证文本,请参阅 [LICENSE.txt](LICENSE.txt)。
标签:GunBound, Netty, 域名枚举, 多人在线游戏, 服务端模拟器, 游戏服务器