Ghi Chú Phát Triển (12): Chiến Lược Đồng Bộ Vị Trí
Trong hai tuần trở lại đây, một vài đồng nghiệp mới đã bắt đầu vào việc hoặc sẽ sớm tham gia. Vì vậy tôi không muốn dành quá nhiều thời gian đi sâu vào các chi tiết kỹ thuật cụ thể nữa. Tốt nhất nên đợi đến khi kế hoạch nhân sự được hoàn tất, mọi người đều có việc để làm rồi hãy tự mình nhận riêng một phần việc cụ thể. Do đó, lượng mã nguồn do tôi trực tiếp viết trong giai đoạn này không nhiều. Chủ yếu tôi chỉ bảo trì lại những module đã xây dựng trước đây và tiến hành bàn giao các đoạn mã đã viết cho những bạn phụ trách cụ thể.
Điều đáng chú ý ở đây là thư viện protobuf C do tôi viết đã dần trở nên sử dụng được. Kể từ khi đưa lên GitHub, đã có hai lỗi được các lập trình viên xa lạ (không quen biết) nhiệt tình chỉ ra. Tất nhiên, trong quá trình tự mình sử dụng tôi cũng phát hiện và sửa nhiều lỗi hơn nữa. Tính đến thời điểm hiện tại có thể xem như đã tương đối hoàn thiện. Trong tương lai sẽ còn dùng nhiều hơn nữa, đợi đến khi toàn bộ dự án hoàn tất mới có thể khẳng định chắc chắn là ổn định. Hiện tại chủ yếu sử dụng phần binding với Lua. Để tiện lợi hơn, hôm qua tôi thậm chí đã tự phát triển một bộ phân tích file proto làm tùy chọn, giúp không còn phụ thuộc vào công cụ biên dịch của Google nữa.
Hai ngày trước chúng tôi tổ chức cuộc họp lập trình định kỳ. Cuộc họp do Dinh Đương chủ trì. Chúng tôi nhận thấy rằng trước khi triển khai công việc trên diện rộng (còn vài lập trình viên và chuyên viên thiết kế chưa到位), chúng tôi cần tận dụng khoảng thời gian cuối cùng này để giải quyết dứt điểm một số vấn đề kỹ thuật trọng tâm. Một trong những việc cấp bách nhất là xử lý đồng bộ vị trí trong game hành động thời gian thực. Việc tạo ra trải nghiệm điều khiển mượt mà không hề dễ dàng, hiện tại các game MMO trong nước chưa thực sự có sản phẩm nào làm tốt điều này. Lấy ví dụ như sản phẩm của NetEase – Thiên Hạ 2 – thì khâu đồng bộ vị trí vẫn còn nhiều điểm yếu.
Chúng tôi đặt mục tiêu tối thiểu phải đạt đến trình độ của World of Warcraft. Ngay cả khi mạng không ổn định, độ trễ dao động từ 200 đến 2000 ms, người chơi vẫn phải có trải nghiệm mượt mà.
Khi nói đến đây, tôi nhớ lại 6 năm về trước chúng tôi cũng đã từng nghiên cứu vấn đề này, viết nhiều đoạn mã để kiểm chứng và đầu tư không ít thời gian công sức. Lần này bạn học cũ của công ty Quái Vật lại bắt đầu nghiên cứu từ đầu bằng cách đọc các bài báo chuyên ngành. Những người từng làm việc này cùng tôi năm xưa đã không còn ở đây nữa, nay đổi sang một đội ngũ hoàn toàn mới, cảm giác vừa quen vừa lạ. Tuy nhiên lần này nền tảng kỹ thuật hoàn chỉnh hơn nhiều, cả công cụ và động cơ (engine) đều đã sẵn sàng, hy vọng sẽ thuận lợi hơn.
Dinh Đương cho rằng vấn đề này cực kỳ quan trọng. Nếu không xử lý tốt từ đầu, sau này khi hàng loạt nhiệm vụ dồn đến, sẽ không còn cơ hội quay lại sửa chữa. Thiên Hạ chính là ví dụ điển hình. Tôi năm xưa cũng nghĩ như vậy nhưng đã tốn quá nhiều thời gian cho nó, dẫn đến mất kiểm soát nhịp độ phát triển dự án. Dưới đây tôi sẽ hệ thống hóa lại toàn bộ suy nghĩ lúc đó, trình bày lại cho rõ ràng, coi như là một tài liệu lưu trữ.
Chúng ta cần đơn giản hóa vấn đề, trước tiên tập trung giải quyết một tập hợp nhỏ các bài toán. Xây dựng hệ thống đủ để có thể thử nghiệm lặp đi lặp lại. Chỉ khi tự mình trải nghiệm mới có thể cải tiến. Nói cách khác, hãy xây dựng nguyên mẫu nhanh và “ăn chính món ăn” (ăn thử sản phẩm của mình). Hiện tại ưu tiên hàng đầu là đồng bộ vị trí giữa các người chơi khác nhau. Hãy tập trung vào bài toán này, xây dựng cả client 3D lẫn server để có thể chạy thử thực tế. Bộ phận IT và bạn học Aply đã dựng môi trường mô phỏng nội bộ để giả lập các tình huống mạng xấu. Chúng ta có công cụ kiểm tra hiệu năng trong môi trường khắc nghiệt tốt hơn nhiều so với trước đây.
Đừng nhìn nhận vấn đề quá phức tạp, cũng đừng dùng những phương pháp quá rườm rà, khó hiểu để giải quyết. Tránh sa đà vào các chi tiết kỹ thuật. Ví dụ, việc đồng bộ thời gian giữa client và server vốn là một vấn đề sâu xa và dễ gây tranh cãi (xem tại đây). Chúng ta sẽ tạm thời xây dựng nguyên mẫu một cách đơn giản nhất bằng giải pháp tối giản.
Trước tiên, chúng ta sẽ thiết kế một giao thức đồng bộ thời gian cơ bản nhất: thống nhất rằng độ chính xác thời gian tối thiểu trong các gói mạng là 10ms (0.01 giây), lấy đây làm đơn vị 1. Mọi sự kiện ngắn hơn ngưỡng này đều coi là xảy ra đồng thời.
Client gửi một giá trị thời gian địa phương của mình đến server, server khi nhận được gói tin sẽ kèm theo thời gian server rồi trả về client. Khi client nhận được gói này, có thể ước tính được thời gian gói tin di chuyển đi và về. Đồng thời gửi lại thời gian địa phương mới kèm theo. Quá trình này giúp server hiểu rõ hơn về độ trễ phản hồi.
Việc diễn giải ý nghĩa cụ thể của thời gian client và server hay giá trị của chúng có thống nhất hay không không quan trọng. Chúng ta đơn giản coi chúng là các thời gian địa phương riêng biệt và dùng giá trị này để tính toán độ chênh lệch thời gian hai bên.
Vì hiện tại chỉ tập trung vào đồng bộ vị trí, bước đầu tiên sẽ tin tưởng dữ liệu từ client. Client gửi tọa độ vị trí hiện tại, vector vận tốc (bao gồm hướng và tốc độ) cùng thời gian đến server. Server khi nhận được sẽ hiểu rằng tại thời điểm này (theo thời gian client), người chơi này ở vị trí nào và di chuyển thế nào. Kết hợp độ chênh lệch thời gian và độ trễ ước tính, server có thể dự đoán trạng thái hiện tại (theo thời gian server). Sau đó broadcast thông tin này đến tất cả người chơi khác.
Mỗi client khi nhận được sẽ dựa vào độ chênh lệch và độ trễ chúng đã ước tính để xác định trạng thái hiện tại của tất cả