1 điểm bởi GN⁺ 2023-09-18 | 1 bình luận | Chia sẻ qua WhatsApp
  • ‘Caves of Qud’ đã tiến hành một bước xác minh kỹ thuật để loại bỏ sự phụ thuộc lâu năm vào Unity và build/khởi động lõi game trên Godot; mục tiêu trước mắt là chạy được ở chế độ ASCII + tile mà chưa cần VFX hay UI hiện đại
  • Công việc được chia thành nhập asset tile, chuyển các assembly C# cốt lõi, và dựng bộ khung render/nhập liệu; các tệp tile BMP cũ đã được chuyển sang PNG để nạp vào Godot
  • 5.641 lỗi của bản build ban đầu đã được giảm dần bằng cách chuyển GeneratedCode, ConsoleLib, Genkit, Language, HistoryKit, Newtonsoft JSON, CodeDom, v.v.; đồng thời bề mặt phụ thuộc vào UnityEngine cũng được thu hẹp bằng stub
  • Các điểm dùng Color, GameObject, AudioSource, Debug.Log và Screen của Unity được xử lý bằng UnityEngineReplacer và các lớp thay thế; còn các lớp chargen và presentation gắn chặt với PlayFab·Unity UI thì được tạm gỡ bỏ hoặc để lại như ứng viên tách thành mô-đun glue
  • Kết quả là khoảng 500 nghìn dòng C# lõi game đã khởi động được trên Godot, cấp frame và chờ input, dù công việc dựng renderer, harness nhập liệu cùng VFX, âm thanh và UI vẫn còn lại

Phạm vi công việc chuyển từ Unity sang Godot

  • Việc port được chia thành ba nhánh
    • Nhập asset: đưa asset tile vào project Godot
    • Chuyển assembly cốt lõi: chuyển XRL Application, tức engine game chính ngoài Unity, cùng GameManager ở phía engine
    • Dựng rig render: sau khi lõi khởi động, nối đầu ra màn hình và input
  • Tạo project Godot “mobile” và sao chép nội dung texture của Qud vào thư mục gốc của project
  • Do Godot không xử lý được các tệp .bmp cũ, các tệp bao gồm tile ASCII đã được chuyển hàng loạt sang PNG
  • Sau khi chuyển đổi, asset đã được nạp, nhưng phải mất khoảng 30 giây mới hiện thanh tiến trình import

Giảm lỗi build và chuyển assembly lõi

  • Sau khi sao chép XRL Application, họ tạo project và solution C# trong Godot, và ở trạng thái ban đầu phát sinh 5.641 lỗi
  • Các thư viện dùng chung như ConsoleLibGenkit được chuyển nguyên khối; còn Kobold, giải pháp sprite/atlasing cũ, thì được quyết định mang sang theo từng tệp sau khi kiểm tra mức độ cần thiết
  • KoboldJSON là thư viện tuần tự hóa JSON đơn giản nên được chuyển nguyên trạng
  • Sau khi thay thế toàn cục 85 điểm dùng Color, số lỗi giảm xuống còn 4.700
  • Khi thêm thư mục GeneratedCode còn thiếu, kết quả sinh mã lớp theo từng event được bao gồm và số lỗi giảm tiếp xuống 1.557
    • Caves of Qud dùng cấu trúc sinh mã các lớp theo từng event với nhiều boilerplate để đạt hiệu năng và bề mặt event strongly typed

Sắp xếp lại phụ thuộc Unity và lớp glue

  • Embark Builder và phần tạo nhân vật chargen có nhiều mã Unity UI, nên đã bị gỡ khỏi bước xác minh kỹ thuật ASCII ban đầu
    • Bản console vẫn chưa có, nhưng kiểm thử ban đầu có thể thực hiện bằng cách tải save game hoặc bắt đầu ngẫu nhiên
  • Thư mục Game phần lớn là glue giữa Unity và game, nhưng cũng có các thư mục không phải glue như CodeGeneration, nên họ chọn hướng chuyển chúng sang một root riêng hoặc thư mục Platform
  • Khi chuyển các thư viện LanguageHistoryKit, số lỗi giảm xuống 454; việc tách biệt game/glue dù chưa hoàn hảo vẫn tỏ ra hữu ích
  • Các nhóm lỗi lớn còn lại là CodeDom/Roslyn, PlayFab, Harmony, một số vấn đề liên quan đến compiler, và bề mặt UnityEngine bị rò lên tầng game
  • Mã liên quan đến PlayFab được tạm thời comment out và để lại như ứng viên đẩy lên mô-đun glue

Stub thay thế API Unity và khác biệt C# của Godot

  • Color32 là kiểu màu dựa trên byte nên một bản thay thế đã được viết nhanh
  • Họ tạo thư mục UnityEngineReplacer và triển khai chỉ những bề mặt cần thiết bằng cách nhìn lỗi biên dịch, không dựa vào tài liệu hay tham chiếu mã của Unity
  • Khi tạo stub cho GameObject, lỗi “không biết GameObject” được chuyển thành lỗi về các field và method thực sự cần thiết, giúp họ nắm được bề mặt interface mà game đang dùng
  • AudioSource cũng được bổ sung từng member một theo danh sách lỗi, và cuối cùng hoàn thiện toàn bộ interface port của AudioSource mà game thực sự sử dụng
  • Các bề mặt khác đã xử lý gồm:
    • shim thay thế Debug.Log
    • bản thay thế Screen
    • chuyển thư viện extension method IsNullOrEmpty
    • xử lý tham chiếu Math và khác biệt PI/Pi
    • xử lý khác biệt tên tọa độ viết hoa X, Y của Godot
    • dọn lỗi IDE import nhầm System.Drawing.Color, System.Numerics.Vector3
  • Newtonsoft JSON được giải quyết bằng cách thêm gói NuGet trong Visual Studio, và CodeDom cũng được xử lý bằng gói NuGet CodeDom

Khởi động toàn bộ trên Godot

  • Khi số lỗi giảm còn 11, vấn đề còn lại liên quan đến mã biên dịch C# động của phần mod management; không bắt buộc nhưng phức tạp nên bị để lại đến cuối
  • Sau đó, họ xử lý giai đoạn link và lỗi field của stub để build được khoảng 500 nghìn dòng C#
  • Bước tiếp theo là tạo một renderer nhỏ và harness nhập liệu để khởi động assembly lõi; mục tiêu là làm cho game chạy được ở chế độ ASCII + tile
  • Trong Godot, họ tạo một scene rỗng và gắn GameManager.cs vào node cơ bản; GameManager kế thừa Node và cần mã partial
  • _Ready của Godot được dùng tương ứng với Awake của Unity, còn _Process tương ứng với Update
  • Trong quá trình khởi tạo, họ chuyển load path và mod management, rồi lần theo kiểu printf vấn đề resolver không tìm được type theo tên
  • Nguyên nhân là xử lý dynamic assembly
    • assembly của mod là dynamic nên khi kiểm tra main assembly, họ đã loại trừ dynamic assembly
    • trong Godot editor, assembly game chính cũng là dynamic nên bị loại khỏi đối tượng tìm type
  • Sau khi sửa, họ đã khởi động toàn bộ thành công, và lõi game 500 kloc đã ở trạng thái cấp frame và chờ input
  • Phần việc còn lại được mô tả là “just work”, nhưng trên thực tế vẫn còn khối lượng đáng kể cho VFX, âm thanh và UI rigging

1 bình luận

 
GN⁺ 2023-09-18
Ý kiến trên Hacker News
  • Trò chơi này dường như gần như hoàn toàn dùng engine tự phát triển, còn Unity chỉ được dùng như lớp trừu tượng hóa phần cứng và khung để port, nên xét về độ khó khi port thì có vẻ gần với trường hợp lý tưởng nhất
    Có khá nhiều game kiểu này một cách đáng ngạc nhiên, nhưng dĩ nhiên chúng không đại diện cho phần lớn các tựa game Unity

    • Đúng vậy. Trong một cuộc phỏng vấn nào đó, họ từng nói Qud lúc ấy chạy bên trong Unity như một ứng dụng console
      Không biết sau khi cải tổ UI thì có còn như vậy không, nhưng nếu đúng thế thì tôi luôn thấy lạ là họ không port sang MonoGame để tiết kiệm chi phí
    • Tôi xem đây là kết quả cho thấy về dài hạn, hầu hết các thành phần cơ bản của Unity gần như đều trở nên vô dụng
      Android cũng tương tự: hệ điều hành chỉ được dùng để gọi các thư viện thay thế cho những thứ như phát hiện camera hay mã hóa, rồi đến một ngày bạn nhận ra hệ điều hành thực chất chỉ là một lớp kim loại mỏng và bootloader
  • https://nitter.net/unormal/status/1703163364229161236

  • Wow, thật tuyệt. Tôi thích việc có thể xem quá trình port này từng bước một, và cũng ngạc nhiên vì thời gian bỏ ra khá hợp lý

    • Godot có ít tính năng hơn nhiều, nhưng tôi nghĩ nó thật sự dễ học
    • Tôi muốn xem họ đã tái hiện bầu không khí thị giác đặc trưng của Caves of Qud trong Godot như thế nào
  • Nếu có nhiều code tùy chỉnh và cấu trúc ít dùng các tính năng của editor, có lẽ dùng thư viện rendering thay cho engine cũng được

    • Nếu muốn phát hành game đồng thời trên nhiều nền tảng, việc tự xử lý code rendering, âm thanh và input riêng cho từng nền tảng sẽ nhanh chóng trở nên chán ngấy
      Có engine làm nền thì bạn có được những thứ này miễn phí. Với Unity thì có thể kèm chi phí
    • Họ đã dùng thư viện rendering rồi. Tên nó là “Unity”
  • Nếu muốn biết Brian nghĩ gì, nên xem video này: https://www.youtube.com/watch?v=U03XXzcThGU
    Trước đây tôi đã học được rất nhiều từ đây

  • Làm tôi nhớ đến tranh cãi TypeScript gần đây của DHH
    Thử tưởng tượng port như thế này mà không có kiểu tĩnh: mỗi lần thay đổi lại phải build, chạy và tìm chỗ crash. Những lúc như vậy mới thật sự biết ơn việc đã xây dựng bằng một ngôn ngữ dễ refactor và một kiến trúc tốt

  • Tôi không có tài khoản Twitter, chuyện gì vậy?