Vấn Đề Chuyển Đổi Dữ Liệu Tài Nguyên
Trong quá trình làm việc với engine game vào tuần trước, chúng tôi gặp một số lỗi liên quan đến thiết kế cũ. Sau vài ngày thảo luận sôi nổi, hôm nay đã thống nhất được giải pháp cuối cùng cần được ghi chép lại chi tiết.
Bản chất vấn đề: Lỗi phát sinh từ quy trình chuyển đổi tài nguyên trò chơi. Các tài nguyên game thường trải qua quá trình chuyển đổi từ định dạng gốc sang định dạng tối ưu cho nền tảng chạy. Ví dụ, file ảnh gốc là PNG nhưng engine yêu cầu định dạng nén phù hợp từng nền tảng - DXT cho Windows và KTX cho di động. Trong các engine thương mại như Unity, quá trình này được xử lý trong workflow nhập tài nguyên.
Thiết kế đặc biệt của chúng tôi: Engine của chúng tôi thực hiện chuyển đổi ở cấp độ hệ thống tệp ảo. Quyết định này xuất phát từ nhận định rằng việc nhập tài nguyên đồng loạt gây phiền toái khi người dùng phải chờ đợi. Mặc dù Unity giải quyết vấn đề này qua cache server, nhưng tôi cho rằng giải pháp đó vẫn còn hạn chế (sẽ phân tích kỹ trong bài viết khác).
Triết lý thiết kế: Tôi muốn xây dựng cơ chế “lười biếng” (lazy) - chỉ chuyển đổi tài nguyên khi thật sự cần trong quá trình chạy. Trong thiết kế hiện hành, mỗi tài nguyên cần chuyển đổi đều đi kèm file .lk cùng tên trong hệ thống tệp. File này chứa thông tin cấu hình chuyển đổi, tương tự như file .meta của Unity.
Cơ chế hoạt động: Khi phát hiện file có .lk, hệ thống tệp ảo sẽ tự động kích hoạt mô-đun xây dựng để chuyển đổi tài nguyên gốc. Ban đầu chúng tôi giả định rằng: hash kết hợp 3 yếu tố (file gốc, file .lk và tham số nền tảng) đủ để xác định duy nhất tài nguyên đầu ra. Giả định này vừa bị phá vỡ khi phát hiện lỗi ở file shader.
Nguyên nhân gốc rễ: Shader là dạng mã nguồn tương tự C/C++, việc biên dịch phụ thuộc vào nhiều file include. Chỉ dùng hash của file shader gốc không đủ để xác định kết quả biên dịch chính xác. Ví dụ: khi sửa file include của shader nhưng hệ thống vẫn trả về kết quả cache cũ do không nhận diện được sự thay đổi.
Giải pháp ban đầu và sự từ chối: Đề xuất đầu tiên là loại bỏ cơ chế xây dựng lười biếng, tách biệt chuyển đổi tài nguyên khỏi fileserver. Đây là cách tiếp cận truyền thống giống Unity - tài nguyên luôn sẵn sàng trước khi chạy. Tuy đơn giản nhưng phương án này bị loại vì quay lại bài toán cũ về thời gian chờ đợi nhập liệu.
Giải pháp tối ưu: Lấy ví dụ với file shader a.sc và file cấu hình a.sc.lk. Khi nhận yêu cầu xây dựng, fileserver sẽ biên dịch lại hoàn toàn cho nền tảng chỉ định và trả về hash kết quả (không cache). Tuy nhiên, hệ thống sẽ tạo file a.sc.lk.ios mới trong hệ thống tệp ảo, chứa:
- Phương pháp xây dựng cụ thể cho iOS
- Danh sách phụ thuộc (đường dẫn các file liên quan)
- Hash hiện tại của các file phụ thuộc
Cơ chế cache thông minh: File .ios này (ẩn với client trong phiên làm việc) chứa đầy đủ thông tin để xác định duy nhất kết quả biên dịch. Bất kỳ thay đổi nào ở file phụ thuộc đều thay đổi hash, buộc hệ thống tạo lại file .ios mới. Khi client truy cập file .ios, fileserver có thể cache kết quả biên dịch dựa trên hash của .ios (chứ không chỉ hash tài nguyên gốc như trước).
Ưu điểm vượt trội:
- Cache đa dự án: Cùng một texture đã biên dịch ở dự án A có thể tái sử dụng kết quả biên dịch khi đưa sang dự án B, khác biệt hoàn toàn với Unity nơi thay đổi vị trí file cũng khiến GUID thay đổi buộc biên dịch lại.
- Dự đoán thông minh: Fileserver có thể nhận diện nhu cầu tương lai (ví dụ: nếu client yêu cầu phiên bản iOS, hệ thống có thể tự động tạo trước phiên bản Android trong thời gian rảnh).
- Quản lý dữ liệu hiệu quả: Tương tự mô hình GitHub Large File Storage, file .ios đóng vai trò như URL trỏ đến kết quả biên dịch thực tế, giúp lưu trữ tập trung mà không gây phình to kho dữ liệu.
So sánh với Unity: Trong khi cache server của Unity chỉ là kho key-value đơn giản, giải pháp của chúng tôi lưu trữ toàn bộ quá trình biên dịch bao gồm các phụ thuộc. Điều này cho phép xác định chính xác kết quả biên dịch và mở ra khả năng cache đa chiều vượt trội.
Triển vọng tương lai: Thiết kế này không chỉ giải quyết vấn đề hiện tại mà tạo nền tảng cho các tính năng thông minh hơn như:
- Tối ưu hóa tự động dựa trên lịch sử sử dụng
- Phân tích phụ thuộc thời gian thực
- Tích hợp với hệ thống CI/CD để tự động tạo tài nguyên cho nhiều nền tảng cùng lúc
Giải pháp này đánh dấu bước tiến quan trọng trong cách quản lý tài nguyên game, kết hợp hài hòa giữa tính linh hoạt và hiệu quả vận hành.