38 KiB
รายงานการวิเคราะห์สถาปัตยกรรมและการทำงานของ LunarCore (Deep-Dive Technical Specification)
เอกสารอ้างอิงทางเทคนิคระดับลึกสำหรับวิศวกรซอฟต์แวร์และโมเดลปัญญาประดิษฐ์ (AI Systems)
วิเคราะห์จากซอร์สโค้ดของโครงการ: Melledy/LunarCore
ครอบคลุมสถาปัตยกรรมระบบ, Binary Network Protocol Framing, State Machine, Authoritative vs Client Simulation, การจัดการข้อมูล (Data & Persistence) และ Gameplay Subsystems ทั้งหมด
สารบัญ (Table of Contents)
- ภาพรวมสถาปัตยกรรมระดับสูง (High-Level Architecture)
- เลเยอร์เครือข่ายและการเข้ารหัสแพ็กเก็ต (Network & Protocol Framing)
- 2.1 วงจร HTTP / Dispatch / Gateway Server
- 2.2 โครงสร้าง Binary Packet Framing (Magic & Header Layout)
- 2.3 กลไก KCP Transport และ GameSession State Machine
- วงจรชีวิตของผู้เล่นและการเชื่อมต่อ (Player Lifecycle & Handshake Flow)
- โครงสร้างข้อมูลและฐานข้อมูล (Persistence & Morphia ODM)
- 4.1 Internal MongoDB vs Standalone MongoDB
- 4.2 การแบ่งแยก Collections และ Document Schema
- ระบบจัดการทรัพยากรเกมและตารางข้อมูล (Game Data & Resource Pipeline)
- ระบบฉากและ Entity ในโลกเปิด (Scene & Entity Engine)
- ระบบการต่อสู้ (Battle Orchestration & Reconciliation)
- ระบบโหมดการเล่นขั้นสูง (Simulated Universe & Challenge Modes)
- ระบบตัวละคร, คลังสัมภาระ และไอเทม (Avatar & Inventory Subsystem)
- 9.1 Multi-Path Switching (ระบบเปลี่ยนคลาส Trailblazer)
- 9.2 ระบบสุ่มค่า Relic (Main Affix & Sub Affix Step Generator)
- ระบบ Gacha และคำสั่งเซิร์ฟเวอร์ (Gacha, Commands & Plugins)
- สรุปข้อสังเกตและคู่มือการนำไปพัฒนาต่อสำหรับ AI
1. ภาพรวมสถาปัตยกรรมระดับสูง (High-Level Architecture)
LunarCore ถูกออกแบบเป็น Server Reimplementation ในภาษา Java (JDK 17+) สำหรับเกม Honkai: Star Rail โดยแบ่งบทบาทการทำงานออกเป็น 2 โดเมนหลัก ในระบบเดียว (สามารถรันแยกกระบวนการหรือรันพร้อมกันได้ผ่านแฟล็ก -dispatch และ -game):
-
Dispatch / HTTP Server (พอร์ตเริ่มต้น: TCP 80 หรือ 443 ผ่าน SSL):
- ทำหน้าที่จำลองระบบ SDK ของ miHoYo / HoYoverse: การลงทะเบียน, ล็อกอิน (OAuth/Password/Cached Token), ตรวจสอบความเสี่ยง (Risk check), ส่งคืนรายการภูมิภาค (Region List) และข้อมูลเกตเวย์ (
query_gateway) - ใช้เฟรมเวิร์ก Javalin (ครอบบน Jetty Server) มีประสิทธิภาพสูงและมี footprint ต่ำ
- ทำหน้าที่จำลองระบบ SDK ของ miHoYo / HoYoverse: การลงทะเบียน, ล็อกอิน (OAuth/Password/Cached Token), ตรวจสอบความเสี่ยง (Risk check), ส่งคืนรายการภูมิภาค (Region List) และข้อมูลเกตเวย์ (
-
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)
- รองรับการเชื่อมต่อแบบ State-full ด้วย KCP protocol over UDP (ใช้ไลบรารี
-
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 แบบอัตโนมัติ
- Quickbuf (
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<br/>/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
ลำดับการเรียกจากไคลเอนต์ก่อนเข้าเกม:
GET /query_dispatch: ไคลเอนต์ขอรายชื่อเซิร์ฟเวอร์- เซิร์ฟเวอร์ตอบกลับด้วย Protobuf
DispatchRegionDataเข้ารหัสเป็น Base64 String บรรจุรายชื่อ Gateway, ชื่อภูมิภาค, Dispatch URL
- เซิร์ฟเวอร์ตอบกลับด้วย Protobuf
POST /hkrpg_global/mdk/shield/api/loginหรือPOST /hkrpg_global/mdk/shield/api/verify:- ไคลเอนต์ส่งบัญชี/รหัสผ่าน หรือโทเค็นเดิม
- เซิร์ฟเวอร์สร้าง Account (ถ้าเปิด
autoCreateAccount) และสร้างsessionKey(SHA-512 Hash)
POST /hkrpg_global/combo/granter/login/v2/login:- ไคลเอนต์นำ
sessionKeyมาแลกเป็นcombo_token
- ไคลเอนต์นำ
GET /query_gateway:- ไคลเอนต์ส่งคำขอ Gateway Info สำหรับการเชื่อมต่อไปยังเกมเซิร์ฟเวอร์
- เซิร์ฟเวอร์ตอบกลับด้วย Protobuf
Gateserverเข้ารหัส Base64 String มีฟิลด์สำคัญ:ip: IP ของ Game Serverport: 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)
// โครงสร้างการเขียนไบนารีใน 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 ControlMTU: 1400 ไบต์Sndwnd / Rcvwnd: 256 / 256 (บัฟเฟอร์การส่งและรับ)Timeout: 30 วินาทีUseConvChannel: เปิดใช้งานรหัส Connection ConversationAckNoDelay: เปิดใช้งาน ACK ทันที
State Machine ของ GameSession:
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
WAITING_FOR_TOKEN: รับได้เฉพาะPlayerHeartBeatCsReqและPlayerGetTokenCsReqเท่านั้น หากส่งแพ็กเก็ตอื่นจะถูกทิ้งทันทีWAITING_FOR_LOGIN: ตรวจสอบบัญชีเสร็จแล้ว รอรับPlayerLoginCsReqACTIVE: เซสชันพร้อมทำงานเต็มรูปแบบ สามารถประมวลผลคำสั่งในเกมได้ทั้งหมดINACTIVE: เซสชันถูกตัด หลุดจากเซิร์ฟเวอร์ จะบันทึกสถานะผู้เล่นลงฐานข้อมูลทันที
3. วงจรชีวิตของผู้เล่นและการเชื่อมต่อ (Player Lifecycle & Handshake Flow)
ลำดับการแลกเปลี่ยนแพ็กเก็ต (Packet Handshake) ขณะล็อกอินเข้าสู่ตัวเกม:
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 รูปแบบ:H2Backend: บันทึกลงดิสก์เป็นไฟล์database.mv(Persist ถาวร)MemoryBackend: รันใน RAM เท่านั้น (ข้อมูลหายเมื่อปิดเซิร์ฟเวอร์)
4.2 การแบ่งแยก Collections และ Document Schema
| Collection | Entity Class | Primary Key | Key Indexes | หน้าที่และรายละเอียดฟิลด์สำคัญ |
|---|---|---|---|---|
accounts |
Account |
String _id |
token, sessionKey |
จัดเก็บข้อมูลล็อกอิน, comboToken, permissions (Set<String>) |
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):
- Reflection Scan: สแกนหาทุกคลาสที่สืบทอดมาจาก
GameResourceและมี Annotation@ResourceType - Priority Ordering: จัดลำดับการโหลดตาม
loadPriorityเพื่อให้ข้อมูลพื้นฐาน (เช่น TextMap, Rarity, Stats) โหลดเสร็จก่อนข้อมูลที่ขึ้นต่อกัน (เช่น Avatars, Relics, Stages) - Custom Deserializers: ใช้ Gson ร่วมกับ TypeAdapter เฉพาะ:
LunarCoreDoubleDeserializer: ป้องกันปัญหาความแม่นยำของเลข Floating-pointLunarCoreHashDeserializer: แปลง Hash String ใน ExcelBin เป็น Integer/Long Key
- 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 ที่อยู่ในฉาก (จุดเกิดของมอนสเตอร์, หีบสมบัติ, เสาฟื้นฟูเลือด, ประตูมิติ)
classDiagram
class Scene {
-Player player
-int planeId
-int floorId
-Int2ObjectMap~GameEntity~ entities
-IntSet avatarEntityIds
+loadGroup(groupId)
+addEntity(entity)
+removeEntity(entity)
+onTick()
}
class GameEntity {
<<interface>>
+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 ในการเตรียมข้อมูลด่าน และตรวจสอบผลลัพธ์หลังสู้เสร็จ
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 ด่านจากStageExcellogicRandomSeed: เลขสุ่ม 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:- เซิร์ฟเวอร์ดึงข้อมูลจาก
MultiplePathAvatarExcel - โหลด
AvatarMultiPathที่บันทึกเลเวลสกิลของ Path นั้นๆ - สลับข้อมูล
skills,equips, และโมเดลเพศ (gender) ในGameAvatar - บันทึกลงตาราง
curAvatarPathsในเอกสารplayers - ส่งแพ็กเก็ต
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#):
- Protocol Framing: ห้ามลืมกรอบ 16 ไบต์เด็ดขาด (
0x9D74C714นำหน้า และ0xD7A152C8ปิดท้าย) หากไบต์ขาดหรือผิดแฮนด์เชกจะค้าง - Gateway Encoding: แพ็กเก็ต HTTP Gateway (
/query_dispatchและ/query_gateway) ต้องแปลงเป็น Protobuf ไบนารีก่อน แล้วค่อยครอบด้วย Base64 String ส่งเป็นเนื้อหา HTTP Response - Turn-based Battle Paradigm: เซิร์ฟเวอร์ไม่ต้องสร้าง AI คำนวณดาเมจต่อเทิร์น แต่ต้องเตรียม
SceneBattleInfoให้ครบถ้วน (ตัวละคร, มอนสเตอร์แต่ละเวฟ, บัฟ, ค่าพลังกาย) แล้วรอรับผลสรุปPVEBattleResultCsReqจาก Client - Data Synchronization (Syncable): หลังการเปลี่ยนแปลงไอเทมหรือตัวละคร ต้องส่ง
PacketPlayerSyncScNotifyเสมอ เพื่อให้หน้าต่าง UI ของเกมแสดงผลตรงกับฐานข้อมูล - Session States: รักษา State Flow ให้เคร่งครัดตามลำดับ
WAITING_FOR_TOKEN->WAITING_FOR_LOGIN->ACTIVEอย่าตอบรับคำสั่งเกมก่อนเซสชันจะอยู่ในสถานะACTIVE