# รายงานการวิเคราะห์สถาปัตยกรรมและการทำงานของ LunarCore (Deep-Dive Technical Specification)
> **เอกสารอ้างอิงทางเทคนิคระดับลึกสำหรับวิศวกรซอฟต์แวร์และโมเดลปัญญาประดิษฐ์ (AI Systems)**
> วิเคราะห์จากซอร์สโค้ดของโครงการ: [Melledy/LunarCore](https://github.com/Melledy/LunarCore)
> ครอบคลุมสถาปัตยกรรมระบบ, Binary Network Protocol Framing, State Machine, Authoritative vs Client Simulation, การจัดการข้อมูล (Data & Persistence) และ Gameplay Subsystems ทั้งหมด
---
## สารบัญ (Table of Contents)
1. [ภาพรวมสถาปัตยกรรมระดับสูง (High-Level Architecture)](#1-ภาพรวมสถาปัตยกรรมระดับสูง-high-level-architecture)
2. [เลเยอร์เครือข่ายและการเข้ารหัสแพ็กเก็ต (Network & Protocol Framing)](#2-เลเยอร์เครือข่ายและการเข้ารหัสแพ็กเก็ต-network--protocol-framing)
- 2.1 วงจร HTTP / Dispatch / Gateway Server
- 2.2 โครงสร้าง Binary Packet Framing (Magic & Header Layout)
- 2.3 กลไก KCP Transport และ GameSession State Machine
3. [วงจรชีวิตของผู้เล่นและการเชื่อมต่อ (Player Lifecycle & Handshake Flow)](#3-วงจรชีวิตของผู้เล่นและการเชื่อมต่อ-player-lifecycle--handshake-flow)
4. [โครงสร้างข้อมูลและฐานข้อมูล (Persistence & Morphia ODM)](#4-โครงสร้างข้อมูลและฐานข้อมูล-persistence--morphia-odm)
- 4.1 Internal MongoDB vs Standalone MongoDB
- 4.2 การแบ่งแยก Collections และ Document Schema
5. [ระบบจัดการทรัพยากรเกมและตารางข้อมูล (Game Data & Resource Pipeline)](#5-ระบบจัดการทรัพยากรเกมและตารางข้อมูล-game-data--resource-pipeline)
6. [ระบบฉากและ Entity ในโลกเปิด (Scene & Entity Engine)](#6-ระบบฉากและ-entity-ในโลกเปิด-scene--entity-engine)
7. [ระบบการต่อสู้ (Battle Orchestration & Reconciliation)](#7-ระบบการต่อสู้-battle-orchestration--reconciliation)
8. [ระบบโหมดการเล่นขั้นสูง (Simulated Universe & Challenge Modes)](#8-ระบบโหมดการเล่นขั้นสูง-simulated-universe--challenge-modes)
9. [ระบบตัวละคร, คลังสัมภาระ และไอเทม (Avatar & Inventory Subsystem)](#9-ระบบตัวละคร-คลังสัมภาระ-และไอเทม-avatar--inventory-subsystem)
- 9.1 Multi-Path Switching (ระบบเปลี่ยนคลาส Trailblazer)
- 9.2 ระบบสุ่มค่า Relic (Main Affix & Sub Affix Step Generator)
10. [ระบบ Gacha และคำสั่งเซิร์ฟเวอร์ (Gacha, Commands & Plugins)](#10-ระบบ-gacha-และคำสั่งเซิร์ฟเวอร์-gacha-commands--plugins)
11. [สรุปข้อสังเกตและคู่มือการนำไปพัฒนาต่อสำหรับ AI](#11-สรุปข้อสังเกตและคู่มือการนำไปพัฒนาต่อสำหรับ-ai)
---
## 1. ภาพรวมสถาปัตยกรรมระดับสูง (High-Level Architecture)
LunarCore ถูกออกแบบเป็น Server Reimplementation ในภาษา Java (JDK 17+) สำหรับเกม *Honkai: Star Rail* โดยแบ่งบทบาทการทำงานออกเป็น **2 โดเมนหลัก** ในระบบเดียว (สามารถรันแยกกระบวนการหรือรันพร้อมกันได้ผ่านแฟล็ก `-dispatch` และ `-game`):
1. **Dispatch / HTTP Server (พอร์ตเริ่มต้น: TCP 80 หรือ 443 ผ่าน SSL)**:
- ทำหน้าที่จำลองระบบ SDK ของ miHoYo / HoYoverse: การลงทะเบียน, ล็อกอิน (OAuth/Password/Cached Token), ตรวจสอบความเสี่ยง (Risk check), ส่งคืนรายการภูมิภาค (Region List) และข้อมูลเกตเวย์ (`query_gateway`)
- ใช้เฟรมเวิร์ก **Javalin** (ครอบบน Jetty Server) มีประสิทธิภาพสูงและมี footprint ต่ำ
2. **Game Server (พอร์ตเริ่มต้น: UDP 23301 ผ่าน KCP Protocol)**:
- รองรับการเชื่อมต่อแบบ State-full ด้วย **KCP protocol over UDP** (ใช้ไลบรารี `kcp.highway.Ukcp` บนพื้นฐานของ Netty buffer)
- จัดการ State ของผู้เล่น, ฉาก (Scene), ตำแหน่งในแผนที่ (Floor/Position), คำสั่งในเกม (Commands), และระบบการต่อสู้ (Battle Setup & Result Validation)
3. **Core Dependencies & Libraries**:
- **Quickbuf (`us.hebi.quickbuf`)**: เอนจิน Protobuf ประสิทธิภาพสูงพิเศษระดับ zero-allocation ทำงานเร็วกว่าและกินแรมน้อยกว่า Google Protobuf Java มาตรฐาน
- **Morphia (`dev.morphia`)**: Object-Document Mapper (ODM) สำหรับติดต่อ MongoDB
- **Mongo Java Server (`de.bwaldvogel`)**: เซิร์ฟเวอร์ MongoDB จำลองในตัวที่ทำงานบนหน่วยความจำหรือ H2 Database Backend ทำให้เซิร์ฟเวอร์รันได้ทันทีโดยไม่ต้องติดตั้ง MongoDB ภายนอก
- **FastUtil (`it.unimi.dsi.fastutil`)**: ไฮสปีด Primitive Collections (`Int2ObjectMap`, `IntSet`, `IntList`) เพื่อลดภาระ Garbage Collection (GC)
- **Reflections (`org.reflections`)**: สแกนหา Controller, Packet Handlers, และ Commands แบบอัตโนมัติ
```mermaid
flowchart TB
subgraph Client["Honkai: Star Rail Game Client"]
ClientHTTP["Client Web/SDK Layer"]
ClientKCP["Client KCP/UDP Transport"]
end
subgraph LunarCoreServer["LunarCore Runtime"]
subgraph HTTPServer["HTTP / Dispatch Server (Javalin/Jetty)"]
AuthRoutes["/mdk/shield/api/login
/combo/granter/login"]
QueryDispatch["/query_dispatch (Region List)"]
QueryGateway["/query_gateway (Base64 Proto)"]
end
subgraph KcpGameServer["Game Server (KcpServer / Netty UDP)"]
KcpListener["GameServerKcpListener"]
Session["GameSession (State & Crypto)"]
PacketRouter["GameServerPacketHandler (CmdId Dispatch)"]
subgraph Subsystems["Core Game Services"]
SceneMgr["Scene & Entity Manager"]
BattleSvc["Battle Service (Setup/Validate)"]
RogueSvc["Simulated Universe (Rogue Engine)"]
GachaSvc["Gacha Service (Hot-reloaded)"]
InvSvc["Inventory & Relic Service"]
end
end
subgraph DataLayer["Persistence & Resources"]
Morphia["Morphia ODM"]
MongoDB[("MongoDB / Internal H2 Mongo")]
GameData["GameData / StarRailData (JSON Excels)"]
end
end
ClientHTTP -->|"HTTP GET/POST"| HTTPServer
ClientKCP <-->|"KCP UDP Packets"| KcpListener
KcpListener --> Session
Session --> PacketRouter
PacketRouter --> Subsystems
HTTPServer --> Morphia
Subsystems --> Morphia
Morphia --> MongoDB
Subsystems --> GameData
```
---
## 2. เลเยอร์เครือข่ายและการเข้ารหัสแพ็กเก็ต (Network & Protocol Framing)
### 2.1 วงจร HTTP / Dispatch / Gateway Server
ลำดับการเรียกจากไคลเอนต์ก่อนเข้าเกม:
1. `GET /query_dispatch`: ไคลเอนต์ขอรายชื่อเซิร์ฟเวอร์
- เซิร์ฟเวอร์ตอบกลับด้วย Protobuf `DispatchRegionData` เข้ารหัสเป็น **Base64 String** บรรจุรายชื่อ Gateway, ชื่อภูมิภาค, Dispatch URL
2. `POST /hkrpg_global/mdk/shield/api/login` หรือ `POST /hkrpg_global/mdk/shield/api/verify`:
- ไคลเอนต์ส่งบัญชี/รหัสผ่าน หรือโทเค็นเดิม
- เซิร์ฟเวอร์สร้าง Account (ถ้าเปิด `autoCreateAccount`) และสร้าง `sessionKey` (SHA-512 Hash)
3. `POST /hkrpg_global/combo/granter/login/v2/login`:
- ไคลเอนต์นำ `sessionKey` มาแลกเป็น `combo_token`
4. `GET /query_gateway`:
- ไคลเอนต์ส่งคำขอ Gateway Info สำหรับการเชื่อมต่อไปยังเกมเซิร์ฟเวอร์
- เซิร์ฟเวอร์ตอบกลับด้วย Protobuf `Gateserver` เข้ารหัส **Base64 String** มีฟิลด์สำคัญ:
- `ip`: IP ของ Game Server
- `port`: KCP Port (ค่าตั้งต้น: 23301)
- `asset_bundle_url`, `ex_resource_url`, `lua_url`, `ifix_url`: URL สำหรับ Hotfix ทรัพยากรเกม
### 2.2 โครงสร้าง Binary Packet Framing (Magic & Header Layout)
ทุกแพ็กเก็ตที่วิ่งผ่าน KCP ระหว่าง Client และ GameServer มีโครงสร้างแบบ Binary Framing ชัดเจนความยาวรวมขั้นต่ำ 16 ไบต์ (Header 12 ไบต์ + Tail 4 ไบต์):
```
+-----------------------------------------------------------------------+
| Offset (Bytes) | Type | Field Name | Description |
+-----------------------------------------------------------------------+
| 0x00 - 0x03 | uint32 BE | HEADER_CONST | 0x9D74C714 (Magic) |
| 0x04 - 0x05 | uint16 BE | cmdId / Opcode | คำสั่ง CmdId (เช่น 11) |
| 0x06 - 0x07 | uint16 BE | head_len | Header Length (มักเป็น 0)|
| 0x08 - 0x0B | uint32 BE | data_len | ขนาดไบต์ของ Protobuf|
| 0x0C - ... | byte[] | proto_data | Protobuf Payload |
| ... - End | uint32 BE | TAIL_CONST | 0xD7A152C8 (Magic) |
+-----------------------------------------------------------------------+
```
- **Magic Header**: `0x9d74c714` (Big-Endian)
- **Magic Tail**: `0xd7a152c8` (Big-Endian)
- **Overhead**: คงที่ 16 ไบต์ (ไม่รวมขนาด Payload)
```java
// โครงสร้างการเขียนไบนารีใน BasePacket.java
byte[] packet = new byte[16 + protoSize];
ProtoSink output = ProtoSink.newInstance(packet, 0, packet.length);
this.writeUint32(output, 0x9d74c714); // Magic Header
this.writeUint16(output, cmdId); // 2 bytes Opcode
this.writeUint16(output, 0); // 2 bytes Head Size
this.writeUint32(output, protoSize); // 4 bytes Body Size
if (this.data != null) {
this.data.writeTo(output); // Serialized Protobuf
}
this.writeUint32(output, 0xd7a152c8); // Magic Tail
```
### 2.3 กลไก KCP Transport และ GameSession State Machine
KCP ได้รับการปรับแต่งค่าผ่าน `ChannelConfig` ใน `GameServer.start()`:
- `nodelay(true, 40, 2, true)`: โหมด nodelay เต็มรูปแบบ, Interval 40ms, Resend 2, ปิด Congestion Control
- `MTU`: 1400 ไบต์
- `Sndwnd / Rcvwnd`: 256 / 256 (บัฟเฟอร์การส่งและรับ)
- `Timeout`: 30 วินาที
- `UseConvChannel`: เปิดใช้งานรหัส Connection Conversation
- `AckNoDelay`: เปิดใช้งาน ACK ทันที
#### State Machine ของ GameSession:
```mermaid
stateDiagram-v2
[*] --> WAITING_FOR_TOKEN: KCP Connection Established
WAITING_FOR_TOKEN --> WAITING_FOR_LOGIN: Recv PlayerGetTokenCsReq (Auth OK)
WAITING_FOR_LOGIN --> ACTIVE: Recv PlayerLoginCsReq
ACTIVE --> ACTIVE: Normal Game Packets & Heartbeat
ACTIVE --> INACTIVE: Disconnect / Timeout / Kicked
WAITING_FOR_TOKEN --> INACTIVE: Bad Token / Full Server
INACTIVE --> [*]: Cleanup & Save to DB
```
1. **`WAITING_FOR_TOKEN`**: รับได้เฉพาะ `PlayerHeartBeatCsReq` และ `PlayerGetTokenCsReq` เท่านั้น หากส่งแพ็กเก็ตอื่นจะถูกทิ้งทันที
2. **`WAITING_FOR_LOGIN`**: ตรวจสอบบัญชีเสร็จแล้ว รอรับ `PlayerLoginCsReq`
3. **`ACTIVE`**: เซสชันพร้อมทำงานเต็มรูปแบบ สามารถประมวลผลคำสั่งในเกมได้ทั้งหมด
4. **`INACTIVE`**: เซสชันถูกตัด หลุดจากเซิร์ฟเวอร์ จะบันทึกสถานะผู้เล่นลงฐานข้อมูลทันที
---
## 3. วงจรชีวิตของผู้เล่นและการเชื่อมต่อ (Player Lifecycle & Handshake Flow)
ลำดับการแลกเปลี่ยนแพ็กเก็ต (Packet Handshake) ขณะล็อกอินเข้าสู่ตัวเกม:
```mermaid
sequenceDiagram
autonumber
actor Client as Game Client
participant KCP as GameServer (KCP)
participant Session as GameSession
participant DB as MongoDB
Client->>KCP: KCP Connect Handshake
KCP->>Session: Create Session (State = WAITING_FOR_TOKEN)
Client->>Session: PlayerGetTokenCsReq (AccountUid, Token)
Session->>DB: Query Account by Uid & Validate Token
Session->>DB: Query Player (or create new if null)
Session->>Session: player.onLogin() (Load Avatars, Inventory, Lineup)
Session->>Session: State = WAITING_FOR_LOGIN
Session-->>Client: PlayerGetTokenScRsp (Uid, BlackInfo)
Client->>Session: PlayerLoginCsReq
Session->>Session: State = ACTIVE
Session-->>Client: PlayerLoginScRsp (BasicInfo, ServerTime, Stamina)
Session-->>Client: StaminaInfoScNotify
Client->>Session: PlayerLoginFinishCsReq
Session-->>Client: PlayerLoginFinishScRsp
Session-->>Client: GetArchiveDataScRsp
Session-->>Client: BattlePassInfoNotify
Session-->>Client: ContentPackageGetDataScRsp
Client->>Session: GetCurSceneInfoCsReq
Session-->>Client: GetCurSceneInfoScRsp (SceneInfo, Entities, Lineup)
Client->>Session: EnterSceneCsReq (Teleport / Map Loaded)
Session-->>Client: EnterSceneScRsp
Session-->>Client: SceneEntityMoveScNotify (Spawn Avatar in Scene)
```
---
## 4. โครงสร้างข้อมูลและฐานข้อมูล (Persistence & Morphia ODM)
### 4.1 Internal MongoDB vs Standalone MongoDB
LunarCore รองรับสองโหมดการทำงานของฐานข้อมูลผ่าน `Config.DatabaseInfo`:
- **โหมดภายนอก (External MongoDB)**: ต่อไปยัง MongoDB Server ปกติ (เช่น `mongodb://localhost:27017`)
- **โหมดภายใน (Internal MongoDB Server)**: เริ่มต้นเซิร์ฟเวอร์จำลองด้วย `de.bwaldvogel.mongo.MongoServer` โดยเลือก Backend ได้ 2 รูปแบบ:
1. `H2Backend`: บันทึกลงดิสก์เป็นไฟล์ `database.mv` (Persist ถาวร)
2. `MemoryBackend`: รันใน RAM เท่านั้น (ข้อมูลหายเมื่อปิดเซิร์ฟเวอร์)
### 4.2 การแบ่งแยก Collections และ Document Schema
| Collection | Entity Class | Primary Key | Key Indexes | หน้าที่และรายละเอียดฟิลด์สำคัญ |
|---|---|---|---|---|
| `accounts` | `Account` | `String _id` | `token`, `sessionKey` | จัดเก็บข้อมูลล็อกอิน, comboToken, permissions (`Set`) |
| `players` | `Player` | `int _id (uid)` | `accountUid` | ข้อมูลหลัก: ชื่อ, เลเวล, ค่าเงิน (`scoin`, `hcoin`, `mcoin`), Stamina, พิกัดตำแหน่งฉากล่าสุด (`planeId`, `floorId`, `pos`, `rot`) |
| `avatars` | `GameAvatar` | `ObjectId _id` | `ownerUid` | ตัวละครที่ครอบครอง: `avatarId`, `level`, `promotion`, `rank` (Eidolon), `skills` (Tree points), `equips` |
| `items` | `GameItem` | `ObjectId _id` | `ownerUid`, `equipAvatarId` | ไอเทมทุกประเภท: Relics (Main/Sub affixes), Light Cones (level, rank), Materials, Currencies |
| `lineups` | `PlayerLineup` | `ObjectId _id` | `ownerUid` | จัดทีม 4 ตำแหน่ง, ผู้นำทีม (`leader`), สกิลพอยต์ (`mp`) |
| `extra_lineups` | `PlayerExtraLineup` | `ObjectId _id` | `ownerUid` | ทีมพิเศษสำหรับ Memory of Chaos, Simulated Universe, Trial |
| `challenges` | `ChallengeHistory` | `ObjectId _id` | `ownerUid` | บันทึกสถิติด่าน Forgotten Hall / Pure Fiction (ดาวที่ได้, รอบที่ใช้) |
| `mail` | `Mail` | `ObjectId _id` | `ownerUid` | จดหมายในเกม: หัวข้อ, เนื้อหา, วันหมดอายุ, ของแนบ (`attachments`) |
| `roguetalents`| `RogueTalentData` | `ObjectId _id` | `ownerUid` | อัปเกรดแผนผังพรสวรรค์ของ Simulated Universe |
> [!IMPORTANT]
> **การแยกความสัมพันธ์แบบ Loose Coupling ใน Inventory & Avatar:**
> ฟิลด์ `equips` ในคลาส `AvatarData` ถูกตั้งค่าเป็น `transient` โดยที่ตัวเก็บข้อมูลจริงคือ `GameItem` ที่มีฟิลด์ `@Indexed ObjectId equipAvatarId` เมื่อโหลดเกม ระบบจะ query ไอเทมทั้งหมดในคอลเลกชัน `items` ที่มี `ownerUid` ตรงกัน แล้วเชื่อมโยงเข้ากับอ็อบเจกต์ตัวละครในหน่วยความจำ วิธีนี้ป้องกันปัญหา Data Desync ระหว่างช่องเก็บของและตัวละครอย่างสมบูรณ์
---
## 5. ระบบจัดการทรัพยากรเกมและตารางข้อมูล (Game Data & Resource Pipeline)
ข้อมูลเกมทั้งหมด (Game Data) อ่านมาจากไฟล์ JSON ของเกม ซึ่งดึงมาจากคลังทรัพยากร เช่น `StarRailData` ของ Dimbreath:
- ไดเรกทอรี: `resources/ExcelOutput/`
- ไดเรกทอรีแผนที่: `resources/Config/LevelOutput/RuntimeFloor/`
### วงจรการโหลดข้อมูล (`ResourceLoader.java`):
1. **Reflection Scan**: สแกนหาทุกคลาสที่สืบทอดมาจาก `GameResource` และมี Annotation `@ResourceType`
2. **Priority Ordering**: จัดลำดับการโหลดตาม `loadPriority` เพื่อให้ข้อมูลพื้นฐาน (เช่น TextMap, Rarity, Stats) โหลดเสร็จก่อนข้อมูลที่ขึ้นต่อกัน (เช่น Avatars, Relics, Stages)
3. **Custom Deserializers**: ใช้ Gson ร่วมกับ TypeAdapter เฉพาะ:
- `LunarCoreDoubleDeserializer`: ป้องกันปัญหาความแม่นยำของเลข Floating-point
- `LunarCoreHashDeserializer`: แปลง Hash String ใน ExcelBin เป็น Integer/Long Key
4. **Depot Caching (`GameDepot.java`)**: สร้างแคชสำหรับค้นหาอย่างรวดเร็ว เช่น:
- ตารางน้ำหนักการสุ่ม Main Affix ของ Relic แยกตามชิ้นส่วน
- ตารางการสุ่ม Sub Affix และอัตราการเติบโตเมื่ออัปเกรด
- ตาราง Drop Group และ Monster Wave Templates
---
## 6. ระบบฉากและ Entity ในโลกเปิด (Scene & Entity Engine)
ระบบฉากของ LunarCore ถูกควบคุมด้วยคลาส `Scene.java` โดยอิงตามแนวคิดของเกม:
- **Plane (`MazePlaneExcel`)**: ขอบเขตของแผนที่หลัก (เช่น Space Station, Jarilo-VI, Xianzhou Luofu, Penacony)
- **Floor (`FloorInfo`)**: ชั้นย่อยในฉากนั้นๆ (โหลดมาจาก `LevelOutput/RuntimeFloor/*.json`)
- **Groups (`GroupInfo`)**: กลุ่มของ Entity ที่อยู่ในฉาก (จุดเกิดของมอนสเตอร์, หีบสมบัติ, เสาฟื้นฟูเลือด, ประตูมิติ)
```mermaid
classDiagram
class Scene {
-Player player
-int planeId
-int floorId
-Int2ObjectMap~GameEntity~ entities
-IntSet avatarEntityIds
+loadGroup(groupId)
+addEntity(entity)
+removeEntity(entity)
+onTick()
}
class GameEntity {
<>
+getEntityId() int
+getPos() Position
+getRot() Position
+toProto() SceneEntityInfo
}
class GameAvatar {
-int avatarId
-int currentHp
-int currentSp
}
class EntityMonster {
-int monsterId
-int stageId
-int worldLevel
-boolean isAlive
}
class EntityProp {
-int propId
-PropType propType
-PropState propState
}
class EntityNpc {
-int npcId
-int talkId
}
GameEntity <|.. GameAvatar
GameEntity <|.. EntityMonster
GameEntity <|.. EntityProp
GameEntity <|.. EntityNpc
Scene o-- GameEntity
```
### กลไก Entity ID และ World Sync:
- Entity แต่ละตัวในฉากจะได้ `entityId` แบบ Dynamic ซึ่งเริ่มต้นรันเลขเพิ่มขึ้นเรื่อยๆ ต่อฉาก
- ผู้เล่นส่งพิกัดการเคลื่อนที่ผ่านแพ็กเก็ต `SceneEntityMoveCsReq`
- เซิร์ฟเวอร์อัปเดตพิกัด `pos` และ `rot` ของ `Player` ในหน่วยความจำ และกระจายแพ็กเก็ต `SceneEntityMoveScNotify`
- **ระบบ Space Anchor (เสาฮีล)**: ค้นหาเสาที่ใกล้ที่สุดในฉากผ่าน `Scene.getNearestSpring()` เพื่อใช้เป็นจุดฟื้นฟู HP/MP หรือจุดวาปกลับเมื่อพ่ายแพ้ในการต่อสู้
---
## 7. ระบบการต่อสู้ (Battle Orchestration & Reconciliation)
จุดเด่นของสถาปัตยกรรม Honkai: Star Rail คือ **การจำลองลูปการต่อสู้เทิร์นเบสเกิดขึ้นที่ Client-side ทั้งหมด** โดยเซิร์ฟเวอร์ทำหน้าที่เป็น Authoritative Orchestrator ในการเตรียมข้อมูลด่าน และตรวจสอบผลลัพธ์หลังสู้เสร็จ
```mermaid
sequenceDiagram
autonumber
actor Client as Game Client
participant BattleSvc as BattleService
participant Battle as Battle Instance
participant DropSvc as DropService
Note over Client,BattleSvc: 1. การเปิดฉากต่อสู้ในโลกเปิด
Client->>BattleSvc: SceneCastSkillCsReq (ใช้วิชา Technique หรือโจมตีก่อน)
alt เป็นมอนสเตอร์โจมตีผู้เล่น
BattleSvc->>Battle: สร้าง Battle พร้อม Ambush Buff (1000102)
else เป็นผู้เล่นโจมตีก่อน
BattleSvc->>Battle: สร้าง Battle พร้อม Element Weakness Debuff ของตัวละคร
end
BattleSvc->>Battle: รวบรวม Monster Waves จาก StageExcel
BattleSvc->>Battle: รวบรวมค่าสถานะ HP/SP/Buffs ปัจจุบันของทีม
BattleSvc-->>Client: SceneCastSkillScRsp (SceneBattleInfo Proto)
Note over Client: 2. ไคลเอนต์จำลองการต่อสู้แบบเทิร์นเบสในตัวเครื่อง
Note over Client,BattleSvc: 3. การรายงานผลลัพธ์การต่อสู้
Client->>BattleSvc: PVEBattleResultCsReq (EndStatus, BattleStatistics)
alt ผู้เล่นชนะ (BATTLE_END_WIN)
BattleSvc->>DropSvc: คำนวณรางวัลและของดรอป (Drops)
BattleSvc->>BattleSvc: หักค่าพลังกาย Stamina (ถ้ามี)
BattleSvc->>Client: ลบมอนสเตอร์ตัวนั้นออกจาก Scene
else ผู้เล่นแพ้ (BATTLE_END_LOSE)
BattleSvc->>BattleSvc: รีเซ็ต HP ตัวละครเหลือ 20%
BattleSvc->>Client: วาปตัวละครกลับไปเสา Space Anchor ที่ใกล้ที่สุด
else ผู้เล่นกดยอมแพ้ (BATTLE_END_QUIT)
BattleSvc->>Client: คืนค่าสถานะเดิมและวาปกลับเสา
end
BattleSvc->>BattleSvc: อัปเดต HP และ SP สุทธิของตัวละครลง DB
BattleSvc-->>Client: PVEBattleResultScRsp (รางวัลที่ได้รับ, EXP)
```
### รายละเอียดโครงสร้าง `SceneBattleInfo`:
- `battleId`: เลขรันประจำการต่อสู้ของผู้เล่น
- `stageId`: ID ด่านจาก `StageExcel`
- `logicRandomSeed`: เลขสุ่ม Seed สำหรับให้ Client ใช้คำนวณ Random Roll ในเทิร์น
- `monsterWaveList`: รายการ Wave ของมอนสเตอร์ (Level, Monster ID, Elite Affixes)
- `battleAvatarList`: ข้อมูลตัวละคร 4 ตัวในทีม (Level, Promotion, Relics, Light Cone, ค่า HP/SP ปัจจุบัน)
- `buffList`: บัฟที่ติดมาจากโลกเปิด เช่น ยาบัฟอาหาร, วิชา Technique ก่อนเข้าสู้
- `battleTargetInfo`: เงื่อนไข 3 ดาว สำหรับด่าน Forgotten Hall / Pure Fiction
---
## 8. ระบบโหมดการเล่นขั้นสูง (Simulated Universe & Challenge Modes)
### 8.1 Simulated Universe (Rogue Engine)
ระบบจำลองจักรวาล (Simulated Universe) ถูกแยกการทำงานไว้ในแพ็กเกจ `emu.lunarcore.game.rogue`:
- **`RogueInstance`**: ตัวแทนของรอบการเล่นปัจจุบัน (Run State)
- เก็บค่า `RogueRoomData`: ห้องต่อสู้, ห้อง Elite, ห้องเหตุการณ์ (Event), ห้องพัก (Respite), ห้องบอส
- จัดการสกิลพอยต์จักรวาล Cosmic Fragments (Item ID: 31)
- **ระบบเลือกพร (Blessings / Buffs)**:
- ควบคุมผ่าน `RogueBuffSelectMenu`
- เมื่อชนะห้องต่อสู้ เซิร์ฟเวอร์สุ่มพรตาม Path ที่เลือก และส่ง `AddRogueBuffScNotify`
- **ระบบวัตถุหายาก (Curios / Miracles)**:
- ควบคุมผ่าน `RogueMiracleSelectMenu` ให้ผู้เล่นเลือกรับ Curio
- **ระบบเหตุการณ์โต้ตอบ (Interactive Events)**:
- ควบคุมผ่าน `RogueEventManager` และ `RogueEventInstance`
- ไคลเอนต์ส่ง `SelectRogueCommonDialogueOptionCsReq` เมื่อผู้เล่นเลือกตัวเลือกในเหตุการณ์ เซิร์ฟเวอร์คำนวณผลกระทบ (ได้เงิน, เสียเลือด, ได้พร) แล้วส่งผลลัพธ์กลับ
### 8.2 Forgotten Hall & Pure Fiction (Challenge Subsystem)
- ควบคุมผ่าน `ChallengeManager.java` และ `ChallengeInstance.java`
- จัดการรอบ (Rounds Limit) เช่น กำหนดรอบเหลือไม่ต่ำกว่า 20 เพื่อรับ 3 ดาว
- โหลด Lineup แบบแยกอิสระ (ทีมครึ่งแรก และทีมครึ่งหลัง) ผ่าน `PlayerExtraLineup`
- บันทึกประวัติและดาวที่ทำได้ลงคอลเลกชัน `challenges`
---
## 9. ระบบตัวละคร, คลังสัมภาระ และไอเทม (Avatar & Inventory Subsystem)
### 9.1 Multi-Path Switching (ระบบเปลี่ยนคลาส Trailblazer)
ใน Honkai: Star Rail ตัวเอก (Trailblazer) สามารถเปลี่ยนเส้นทาง Path ได้ (ทำลายล้างกายภาพ, อนุรักษ์ไฟ, ประสานจินตภาพ, ล่าสังหารน้ำแข็ง):
- LunarCore ออกแบบผ่านคลาส `AvatarMultiPath.java`
- เมื่อผู้เล่นกดเปลี่ยน Path ไคลเอนต์จะส่ง `SetAvatarPathCsReq`:
1. เซิร์ฟเวอร์ดึงข้อมูลจาก `MultiplePathAvatarExcel`
2. โหลด `AvatarMultiPath` ที่บันทึกเลเวลสกิลของ Path นั้นๆ
3. สลับข้อมูล `skills`, `equips`, และโมเดลเพศ (`gender`) ใน `GameAvatar`
4. บันทึกลงตาราง `curAvatarPaths` ในเอกสาร `players`
5. ส่งแพ็กเก็ต `PacketAvatarPathChangedNotify` และ `PacketPlayerSyncScNotify` ไปยัง Client
### 9.2 ระบบสุ่มค่า Relic (Main Affix & Sub Affix Step Generator)
การสร้าง Relic ใน `GameItem.java` อิงตามหลักคณิตศาสตร์ของเกมจริง:
```
[Main Affix Allocation]
1. ตรวจสอบชิ้นส่วนของ Relic (Head, Hands, Body, Feet, Planar Sphere, Link Rope)
2. ดึงตาราง MainAffixGroup จาก RelicExcel
3. สุ่มค่า Stat หลักตาม Weight Distribution ใน GameDepot
[Sub Affix Allocation]
1. คำนวณจำนวน Sub Affix เริ่มต้นตาม Rarity:
Base Count = clamp(Rarity - 2, 0, 3) + randomRange(0, 1)
(ตัวอย่างเช่น Relic 5 ดาว จะได้ Sub Affix เริ่มต้น 3 หรือ 4 แถว)
2. สุ่มเลือก Stat รองโดยห้ามซ้ำกับ Main Affix และห้ามซ้ำกับ Sub Affix อื่นที่มีอยู่แล้ว
3. สำหรับแต่ละ Sub Affix จะสุ่มค่า Step (Roll Quality):
Step มีค่า 0, 1, หรือ 2 (แทนค่า Small, Medium, Large Roll)
```
เมื่อมีการอัปเกรด Relic ทุกๆ 3 เลเวล (`HandlerExpUpRelicCsReq`):
- หากจำนวน Sub Affix ยังไม่ครบ 4 แถว ระบบจะเพิ่มแถวใหม่
- หากครบ 4 แถวแล้ว ระบบจะสุ่มเลือก 1 แถวที่มีอยู่เพื่อเพิ่ม `count` และสุ่มค่า `step` ใหม่
---
## 10. ระบบ Gacha และคำสั่งเซิร์ฟเวอร์ (Gacha, Commands & Plugins)
### 10.1 สถาปัตยกรรมตู้กาชา (`GachaService.java`)
- **การ Hot-Reload ด้วย `WatchService`**: ตัวบริการลงทะเบียน File Watcher ตรวจจับไฟล์ `data/Banners.json` หากผู้ดูแลแก้ไขไฟล์ระบบจะ reload ตู้กาชาทันทีโดยไม่ต้องรีสตาร์ตเซิร์ฟเวอร์
- **การคำนวณการันตี (Pity Mechanics)**:
- 5-Star Soft Pity: อัตราพื้นฐาน 0.6% เมื่อเปิดถึงโรลที่ 74 อัตราจะเพิ่มขึ้นแบบเส้นตรงจนถึง 100% ที่โรล 90
- ระบบหลุดเรท 50/50: หากเปิดได้ 5 ดาวที่ไม่ใช่หน้าตู้ ตัวแปร `isFeatured` จะถูกเซ็ตเป็น `true` สำหรับ 5 ดาวรอบถัดไป
- การันตี 4 ดาว: ทุกๆ 10 โรล
### 10.2 เครื่องมือคำสั่งเซิร์ฟเวอร์ (Command Engine)
- ทำงานผ่านทั้งคอนโซลเซิร์ฟเวอร์ และช่องทางแชตในเกม
- ในเกมจะมีบัญชีปลอมชื่อ **"Server" (UID: 99)** ปรากฏในรายชื่อเพื่อนโดยอัตโนมัติ
- ผู้เล่นส่งข้อความที่ขึ้นต้นด้วย `/` หรือ `!` (เช่น `/give 1001`, `/heal`, `/scene 20001 20001001`)
- `ChatManager` จะดักจับข้อความและส่งต่อให้ `CommandManager.invoke(player, message)`
- ตรวจสอบสิทธิ์ผ่านระบบ RBAC: `account.hasPermission(command.permission())`
### 10.3 ระบบปลั๊กอิน (Plugin Architecture)
- รองรับการโหลดไฟล์ JAR จากโฟลเดอร์ `plugins/`
- แต่ละปลั๊กอินมี `plugin.json` ระบุ Main Class, Version, Author
- โหลดผ่าน `URLClassLoader` อิสระ
- มี Lifecycle Hooks: `onLoad()`, `onEnable()`, `onDisable()`
---
## 11. สรุปข้อสังเกตและคู่มือการนำไปพัฒนาต่อสำหรับ AI
หากโมเดล AI ตัวอื่นต้องการนำข้อมูลสถาปัตยกรรมนี้ไปเขียนโค้ดต่อ หรือสร้างเซิร์ฟเวอร์ใหม่ในภาษาอื่น (เช่น Go, Rust, C#):
1. **Protocol Framing**: ห้ามลืมกรอบ 16 ไบต์เด็ดขาด (`0x9D74C714` นำหน้า และ `0xD7A152C8` ปิดท้าย) หากไบต์ขาดหรือผิดแฮนด์เชกจะค้าง
2. **Gateway Encoding**: แพ็กเก็ต HTTP Gateway (`/query_dispatch` และ `/query_gateway`) ต้องแปลงเป็น Protobuf ไบนารีก่อน แล้วค่อยครอบด้วย **Base64 String** ส่งเป็นเนื้อหา HTTP Response
3. **Turn-based Battle Paradigm**: เซิร์ฟเวอร์ไม่ต้องสร้าง AI คำนวณดาเมจต่อเทิร์น แต่ต้องเตรียม `SceneBattleInfo` ให้ครบถ้วน (ตัวละคร, มอนสเตอร์แต่ละเวฟ, บัฟ, ค่าพลังกาย) แล้วรอรับผลสรุป `PVEBattleResultCsReq` จาก Client
4. **Data Synchronization (Syncable)**: หลังการเปลี่ยนแปลงไอเทมหรือตัวละคร ต้องส่ง `PacketPlayerSyncScNotify` เสมอ เพื่อให้หน้าต่าง UI ของเกมแสดงผลตรงกับฐานข้อมูล
5. **Session States**: รักษา State Flow ให้เคร่งครัดตามลำดับ `WAITING_FOR_TOKEN` -> `WAITING_FOR_LOGIN` -> `ACTIVE` อย่าตอบรับคำสั่งเกมก่อนเซสชันจะอยู่ในสถานะ `ACTIVE`