# รายงานการวิเคราะห์สถาปัตยกรรมและการทำงานของ 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`