Kiến trúc
Stack chia làm ba phần: tầng game viết bằng C++ không giữ state, tầng Java giữ toàn bộ state, và hai dịch vụ nhỏ tự viết mà bản backup gốc thiếu.
Luồng kết nối
Phần tiêu đề “Luồng kết nối”flowchart LR
subgraph may["Máy người chơi"]
launcher["launcher"]
clientexe["client.exe"]
end
subgraph native["Tầng C++, không giữ state"]
login["loginserver"]
proxy["proxyserver"]
channel["channelserver ×4"]
gameserver["gameserver, mỗi trận một tiến trình"]
end
subgraph ours["Hai dịch vụ tự viết"]
authsvc["auth (SOAP)"]
patch["patch host"]
end
subgraph java["Tầng Java, giữ toàn bộ state"]
go["go"]
end
mysqlauth[("MySQL.auth")]
mysqlgo[("MySQL.go")]
launcher -->|9531| login
launcher -->|8899| patch
launcher -.->|ticket| clientexe
login --> authsvc
authsvc --> mysqlauth
login -->|9530| proxy
clientexe -->|9500| proxy
proxy -->|8082| go
proxy -->|9501| channel
channel --> gameserver
channel -->|8082| go
go --> mysqlgo
Launcher gọi login server ở 9531 rồi nhận về một ticket. client.exe cầm ticket đó nối vào proxy ở
9500. Bốn channel server ở 9511-9514 lo các phòng, mỗi trận đẻ ra một gameserver riêng.
Cả tầng này không giữ state. Người chơi, item, quest, shop, guild, ranking, mail, đấu giá đều nằm ở
tầng Java (server/go). Tầng C++ gọi sang đó bằng RPC trên 8082, còn MySQL thì thuộc về tầng Java.
Hai dịch vụ còn lại không có trong backup nên phải tự viết: credential service để login server gọi thay vì tin lời client, và patch host để launcher lấy manifest.
Đo bằng netstat -tlnp trong container ngày 2026-08-07. Tầng C++ mở mười một listener, bản chỉ phục
vụ người chơi chỉ publish bảy trong số đó.
Được publish
Phần tiêu đề “Được publish”| Cổng | Process | Vì sao cần đến được |
|---|---|---|
| 843 | authenticationserver | Flash socket-policy server |
| 9500 | proxyserver | điểm vào của client |
| 9505 | socialserver | bạn bè và social, có token gate từ proxy |
| 9511-9514 | channelserver ×4 | bốn kênh game |
| 9531 | loginserver phía client | cấp ticket |
| 8899 | patch host | RemoteURL trong launch.ini |
Cổng 8899 nằm ngay trên đường đăng nhập chứ không phải thứ có cũng được. Bấm LOGIN là kéo
ServerList/recommend.xml, bấm ENTER là kéo GameUpdate/update.xml. Không tới được cổng này thì
launcher bắn CURLE_COULDNT_CONNECT và game không khởi động nổi, nên nó cần uptime ngang login
server.
Nó cũng phải giữ nguyên HTTP thường. libcurl trong launcher không có TLS, đưa https:// vào là
nhận CURLE_UNSUPPORTED_PROTOCOL.
Không được publish
Phần tiêu đề “Không được publish”| Cổng | Process | Kẻ tấn công lấy được gì |
|---|---|---|
| 8082 | infoserver (Java) | trọn bộ servlet bus. Mọi bean s_* nằm ở đây, kể cả gmUserService. Nối thẳng vào 8082 là đi vòng qua proxy, mất luôn ranh giới RPC |
| 8080 | infoserver web (Jetty) | GM console: sửa người chơi, ban, và một màn CRUD cho mọi bảng nội dung |
| 9560 | watchserver phía game | luồng frame của trận đang diễn ra. Không auth, không token |
| 9550 | watchserver phía client | spectate, chỉ GM dùng được. Publish khi nào thật sự deploy client GM, và firewall về đúng địa chỉ GM |
| 9501-9504, 9506, 9520, 9530 | proxy nội bộ, apexproxy, matchingserver, loginserver phía proxy | đã bind 127.0.0.1 theo as_config. Đừng publish, và đừng sửa thành 0.0.0.0 |
| 3306, 11211, 8090 | MySQL, memcached, auth SOAP | chỉ dùng ở back-end |
Trong stack Docker thì chính các container đóng vai firewall: chỉ publish cổng phía người chơi, còn
lại để hết trên bridge nội bộ asnet, nơi as_config gọi nhau bằng IP container.
Muốn kiểm một bản deploy thì quét cổng từ ngoài vào. Đúng ra chỉ mở 843, 9500, 9505, 9511, 9512, 9513, 9514, 9531, 8899. Thấy thêm cổng nào là sai.
Không binary nào bị sửa
Phần tiêu đề “Không binary nào bị sửa”Client, mười một server C++ và tầng Java đều là binary gốc của nhà phát hành. Thứ dựng lại chỉ gồm database nội dung, hai dịch vụ còn thiếu, và đống cấu hình để cả bộ khởi động được.
Cái đó chi phối mọi cách làm trong tài liệu này. Không vá được client thì thêm nội dung phải đi qua
đúng những kênh client vốn đã tin: delta.dat cho tài nguyên, các bảng SYS_*
cho phần còn lại.
Bản nháp đang review. Nội dung nội bộ, đừng chia sẻ ra ngoài nhóm.