Hệ Thống Vá Và Cập Nhật Gói Dữ Liệu Trò Chơi - nói dối e blog

Hệ Thống Vá Và Cập Nhật Gói Dữ Liệu Trò Chơi

Động cơ trò chơi của chúng tôi được xây dựng dựa trên hệ thống tệp ảo (VFS), cho phép ánh xạ thư mục từ máy phát triển lên thiết bị di động thông qua mạng. Điều này mang lại sự tiện lợi lớn trong quá trình phát triển - chỉ cần chỉnh sửa tài nguyên trên máy tính cá nhân, lập tức thay đổi sẽ được phản ánh trên thiết bị di động. Tuy nhiên, khi trò chơi chính thức phát hành (đây là công việc chúng tôi đang chuẩn bị), chúng tôi cần đóng gói toàn bộ tài nguyên và thực hiện cập nhật theo phương thức tải xuống bản vá toàn phần khi có phiên bản mới.

Trước đây vì thiếu thời gian nên chưa triển khai hệ thống này, gần đây chúng tôi mới bắt đầu xem xét thiết kế hệ thống cập nhật phù hợp. Làm thế nào để xây dựng một hệ thống vá hiệu quả? Đây không phải là lần đầu tiên tôi tiếp cận vấn đề này - cách đây hơn 20 năm tôi đã từng thiết kế một hệ thống tương tự cho trò chơi Đại Thoại Tây Du. Tuy nhiên lần này tôi muốn tiếp cận theo hướng hiện đại hơn, sử dụng các công nghệ tiêu chuẩn như định dạng ZIP thay vì tự thiết kế định dạng riêng.

Vấn đề chính không nằm ở cách đóng gói tài nguyên, mà ở cơ chế cập nhật chênh lệch giữa các phiên bản. Dù người dùng đang ở phiên bản nào, hệ thống cũng phải đảm bảo họ có thể cập nhật chính xác lên phiên bản mới nhất. Tốt hơn nữa, hệ thống nên hỗ trợ khả năng quay lui phiên bản (rollback) khi cần thiết.

Phương pháp truyền thống sử dụng số phiên bản tăng dần, chỉ đóng gói sự khác biệt giữa các phiên bản. Khi cập nhật, người dùng phải tải về tất cả các tệp vá từ phiên bản hiện tại đến phiên bản mới nhất theo đúng thứ tự. Mặc dù phương pháp này ổn định, nhưng có nhược điểm là thiếu tính linh hoạt - chỉ cần thiếu một tệp vá là quá trình cập nhật thất bại. Khi số lượng phiên bản tăng lên, số lượng tệp vá cũng phình to đáng kể. Dù có thể định kỳ tạo gói toàn phần để giảm số lượng tệp vá, nhưng đây chỉ là giải pháp tạm thời và không thực sự hiệu quả. Việc quay lui phiên bản hay phát hành các nhánh phiên bản song song cũng trở nên phức tạp hơn.

Hệ thống VFS của chúng tôi thực chất là một cấu trúc Merkle Tree. Tên tệp của mỗi tài nguyên chính là giá trị băm (hash) của nội dung tệp đó, và giá trị băm gốc của cả cây Merkle này tự động trở thành số phiên bản. (Nhân tiện, cơ chế này cũng tự nhiên chống lại việc giả mạo dữ liệu). Việc đóng gói phiên bản đơn giản là tạo một gói chứa toàn bộ các tệp trong cây Merkle tại thời điểm hiện tại, tên của gói này chính là giá trị băm gốc - hay nói cách khác là số phiên bản.

Với cách tiếp cận này, số phiên bản không còn là dãy số tăng dần nữa. Việc chuyển đổi giữa các phiên bản cũng không cần phân biệt là cập nhật, quay lui hay phân nhánh. Điều này tương tự như cách quản lý phiên bản của Git, và hệ thống VFS của chúng tôi cũng hoạt động theo nguyên tắc tương tự, chỉ khác là giờ đây chúng tôi cần giải quyết bài toán đóng gói bản vá.

Mục tiêu của bản vá là giảm băng thông truyền tải và tiết kiệm không gian lưu trữ trên thiết bị người dùng. Vì tên tệp trong VFS chính là giá trị băm nội dung, nên việc tạo bản vá đơn giản là tìm ra các tệp mới được thêm vào. Giả sử máy chủ đã lưu trữ nhiều phiên bản lịch sử, chúng tôi chỉ cần so sánh danh sách tệp phiên bản hiện tại với các phiên bản cũ để tìm ra phiên bản có số lượng tệp mới ít nhất, sau đó đóng gói các tệp mới này.

Trong gói dữ liệu, chúng tôi sẽ bổ sung một số thông tin siêu dữ liệu: đây là gói vá, phiên bản đầy đủ phụ thuộc vào một phiên bản hash khác. Khi người dùng cập nhật, chỉ cần tải về tệp có tên là hash phiên bản mục tiêu (máy chủ cập nhật chứa danh sách tất cả phiên bản và phiên bản đề xuất). Sau khi tải về, hệ thống sẽ kiểm tra siêu dữ liệu để xác định các phiên bản hash phụ thuộc đã tồn tại trên thiết bị chưa. Nếu chưa, quá trình tải sẽ tiếp tục lặp lại cho đến khi đầy đủ.

Ưu điểm của giải pháp này là hoàn toàn tương thích với quá trình đồng bộ VFS trong phát triển hàng ngày. Dù bạn đã đồng bộ các phiên bản phát triển (có thể chưa từng phát hành chính thức), hệ thống vẫn có thể tìm ra các tệp vá cần thiết để hoàn thiện tài nguyên trên thiết bị lên phiên bản đầy đủ.

Trong giải pháp này, chúng tôi không phân biệt giữa gói đầy đủ và gói vá - tất cả đều đại diện cho một phiên bản cụ thể, chỉ khác nhau ở mức độ đầy đủ của dữ liệu bên trong. Mỗi gói sẽ chứa ba thông tin siêu dữ liệu quan trọng:

  1. Hash gốc của phiên bản này là tệp nào - Thông thường tên tệp của gói chính là hash này, nhưng thông tin này sẽ được lưu trong siêu dữ liệu để không phụ thuộc vào tên tệp, giúp tên gói có thể linh hoạt hơn.

  2. Dữ liệu trong gói phụ thuộc vào những phiên bản hash nào khác - Nếu gói không chứa đầy đủ tài nguyên, hệ thống sẽ biết cần tải thêm các gói phụ thuộc nào để hoàn thiện phiên bản.

  3. Phiên bản mã nhị phân tương thích với gói này - Thường là giá trị hash Git của mã nguồn. Vì tệp thực thi không nằm trong gói tài nguyên, nên cần thông tin này để kiểm tra tương thích khi chạy chương trình.

0%