Bỏ qua để đến nội dung

Tra cứu

Tất cả đều là {RemoteURL} cộng đường dẫn. RemoteURL bắt buộc kết thúc bằng /, vì launcher ghép chuỗi trần ("%sGameUpdate/update.xml") chứ không tự chèn dấu phân cách.

GameUpdate/update.xml manifest của game, cái quan trọng nhất
LuncherUpdate/update.xml manifest của chính launcher
ServerList/list.xml danh sách server (danh sách thật đến từ login reply)
ServerList/recommend.xml gọi khi bấm LOGIN
Update/Luncher/asup.exe chính file updater
Thao tác Launcher tải gì
launcher mở lên không gì cả
bấm LOGIN ServerList/recommend.xml (×2)
bấm ENTER ở chọn server GameUpdate/update.xml (×4), rồi từng <Url>, rồi update.xml lần nữa

Payload bị tải hai lần. Cứ tính gấp đôi băng thông.

Manifest không có root element. CurVersionUpdateVersion là hai node ngang hàng ở cấp cao nhất. Đừng bọc chúng lại cho gọn, code parse gọi FirstChildElement thẳng trên document.

Field Ý nghĩa
CurVersion (text) version kênh này đang rao. Update chỉ chạy khi CurVersion > local. Đây là thứ làm update dừng lại.
SrcVer version mà block này nâng cấp từ, so bằng nhau với version dưới máy. * là wildcard, khớp mọi client.
DstVer version block nâng cấp lên. Không phải cổng gì cả.
<Url> text đường dẫn dưới {RemoteURL} để tải. Thiếu text thì tải về 0 byte và báo thành công.
PatchName tên file lúc staging
FileName đường dẫn đích, tính từ thư mục client. Dùng \ được. Ở mode Patch thì để rỗng.
PatchMode Replace cho cả file, Patch để chèn file vào .pde

Chuỗi version phải có đúng bốn phần cách nhau bằng dấu chấm. Ba hay năm phần thì parse hỏng mà không báo, cả block bị bỏ qua.

Wildcard chỉ ăn ở chỗ caller bật cờ cho phép. Version dưới máy được parse với cờ tắt, nên * không bao giờ thay được nó.

Đo qua bốn lần chạy, DstVerCurVersion đều là 1.4.0.64566:

SrcVer published client.exe version Kết quả
* 1.4.0.64564 tải
1.4.0.64564 1.4.0.64564 tải
1.4.0.64560 1.4.0.64564 không rao, dù 64564 < DstVer
1.4.0.64564 1.4.0.64566 không rao

Release bình thường thì dùng --src-version '*' và ship kèm client.exe đã stamp. Chỉ pin SrcVer cụ thể khi cố ý loại bớt máy.

Dấu * phải sống sót qua shell. Câu ssh asbox "wsl python3 … --src-version *" sẽ bị glob-expand theo home directory của máy từ xa. Viết thành ssh asbox "wsl sh -c \"set -f; python3 … --src-version * …\"".

Mỗi dòng: chữ opcode ở byte đầu, đường dẫn bắt đầu từ offset 2.

Op Ý nghĩa
P <archive> mở archive ra làm mục tiêu. Op nào sau đó có đường dẫn bắt đầu bằng <archive>\ thì áp bên trong archive đó
A <relpath> thêm, tự tạo thư mục nếu thiếu
U <relpath> ghi đè, không tạo thư mục
D <relpath> xóa
S <number> ghi vào một biến global đếm tiến độ

B, C, E tới O, Q, R, T, và mọi thứ ngoài khoảng AU đều rơi vào nhánh default rồi bị bỏ qua, không báo gì. Gõ nhầm một chữ opcode là mất nguyên dòng đó.

Client định tuyến bằng cách tra đường dẫn chứ không theo P gần nhất. Op nào có thành phần đầu của đường dẫn trùng một archive đã đăng ký thì rơi vào archive đó, còn lại ghi file ra thư mục client.

U lên một path đã có để lại đúng một entry, nó thay tại chỗ chứ không tạo bản trùng.

D trên một thư mục thì chưa ai thử. diff_pde.py chỉ sinh op cho file, thư mục mất hết file thì nó báo lại rồi để nguyên.

Con số trong Error Code=0x...id của chính câu thông báo đang hiện, không phải status code. Nhánh hiện nó truyền hằng 0 vào tham số format.

Code Thông báo Chỗ bắn ra
-1 0x40000059 update game failed fallthrough, có kèm tham số
-2 0x40000056 download timeout hàm download
-3 0x40000057 file not exist hàm download
-4 0x40000058 size error hàm download
-5 (không hiện dialog) bị hủy
-6 0x4000005a “Auto patch” / unpack applier
-7 (không hiện dialog)

0x4000005a nghĩa là tải về thì xong, CopyFileW đè lên file đang sống thì chết. Gần như luôn là do game vẫn đang chạy.

Chuỗi thông báo nằm trong LanguageDll.dll dưới dạng RT_MESSAGETABLE (type 11), 104 message × 5 thứ tiếng. Grep file EXE không ra gì. Bản tiếng Anh cẩu thả nhất trong năm bản, đọc bản tiếng Trung.

Nơi Có phải cổng update không
client.exe VS_FIXEDFILEINFO Có. Launcher tự mở file rồi tự parse
launch.ini [Ver] game Không. asup.exe có ghi, nhưng launcher không đọc để quyết định
avital\launch.ini [Ver] game Không. Không bao giờ được đọc
/version trong mỗi .pde Không. Chưa thấy nó ảnh hưởng gì

Số version hiện ở màn hình chọn nhân vật nằm bên trong image client.exe, không file nào trên đĩa đổi được nó. Sau bản release 1.4.0.64567, chuỗi 1.4.0.64564 không còn ở đâu trên bản cài nữa mà màn hình vẫn hiện 64564. Muốn đổi thì client/set_client_version.py --label sửa cái được in ra, thông qua UI_common_Version trong game_text.lua của từng pack.

Script Làm gì
research/69_patch_channel/diff_pde.py so hai bản build, in danh sách op và trích payload
research/69_patch_channel/make_delta.py đóng gói delta.dat từ danh sách op. Nhớ --check
research/69_patch_channel/publish.py ghi payload và thêm block vào manifest. Chưa emit được block delta
server/patch/publish.py như trên, phía server
server/patch/stamp_version.py đóng dấu version resource của client.exe
server/patch/patchsrv.py patch server. Log mọi request kể cả 404, kèm SENT <path> <bytes>
research/01_pde_archive/pde_pack.py đóng gói một cây thư mục thành .pde
research/16_add_content/fix_idhash_pde.py sửa idHash trong một archive

Hai script publish.py hiện chỉ nhận một --mode chung cho cả block và luôn ghi FileName=<PatchName>. Bản delta cần FileName="" và cần chọn mode riêng cho từng <Url>, nên manifest delta phải gõ tay.

  • Xài chung --out-dir giữa các archive làm file trùng đường dẫn tương đối đè lên nhau. Mỗi archive một thư mục riêng.
  • File op phân tách bằng TAB. Có một file đang ship tên là /ui/skinf/skin_chuancheng_button3_disabled copy.tga.cache, trong tên có dấu cách. Tách theo whitespace thì một op thành năm field và make_delta.py chết với FileNotFoundError: 'copy.tga.cache'.
  • --check bỏ qua .physx.cache, và bắt buộc phải bỏ qua. Đó là họ file duy nhất chưa giải được công thức idHash. Vô hại khi copy nguyên xi byte của nhà phát hành, không vô hại với file .physx tự tạo.
  • idHash phân biệt hoa thường mà archive dùng chữ thường. /ui/skinf/... đúng, /ui/skinF/... sai.
  • Đường dẫn đem đi băm phải có dấu gạch chéo mở đầu.
  • Xác minh bằng hash và bằng màn hình game. Dòng 200 trong access log chỉ chứng minh file đã được gửi, không chứng minh nó đã cài.
  • patchsrv.py phải chạy đa luồng. Launcher là hai HTTP client trong cùng một process, updater và browser control, mà browser thì giữ socket mở sau khi tải xong trang. Trên TCPServer đơn luồng, một kết nối rảnh như vậy chặn mọi request phía sau, làm ENTER hỏng với CURLE_OPERATION_TIMEDOUT trong khi port vẫn nhận kết nối và curl vẫn lấy được manifest.
  • Đừng bao giờ trỏ RemoteURL vào host của nhà phát hành cũ. Manifest bên đó liệt kê client.exe ở mode Replace, và host đó vẫn phân giải được. Nó mà trả lời thì launcher ghi đè binary của mình.

Bản nháp đang review. Nội dung nội bộ, đừng chia sẻ ra ngoài nhóm.