Brian Bucklew, ‘Caves of Qud’u Unity’den Godot’ya taşıyor
(twitter.com/unormal)- ‘Caves of Qud’, uzun süredir devam eden Unity bağımlılığını ortadan kaldırmak için oyun çekirdeğini Godot üzerinde derleyip başlatmaya yönelik bir teknik doğrulama yürüttü; ilk hedef, modern VFX veya UI olmadan ASCII+tile modunda çalıştırmak
- Çalışma; tile varlıklarını içe aktarma, temel C# assembly’lerini taşıma ve render/input düzenini kurma olarak üçe ayrıldı; eski BMP tile dosyaları PNG’ye dönüştürülerek Godot’ya yüklendi
- İlk derlemedeki 5.641 hata; GeneratedCode, ConsoleLib, Genkit, Language, HistoryKit, Newtonsoft JSON, CodeDom vb. taşınarak azaltıldı ve UnityEngine bağımlılık yüzeyi stub’larla daraltıldı
- Unity’nin Color, GameObject, AudioSource, Debug.Log, Screen kullanım noktaları UnityEngineReplacer ve alternatif sınıflarla ele alındı; PlayFab ve Unity UI’a yakın chargen/presentation katmanları geçici olarak kaldırıldı veya glue modüllerine ayrılacak adaylar olarak bırakıldı
- Sonuçta yaklaşık 500 bin satırlık C# oyun çekirdeği Godot’ta başlatılıp frame üretecek ve input bekleyecek aşamaya geldi; ancak renderer/input harness’i ile VFX, ses ve UI bağlama işleri hâlâ duruyor
Unity’den Godot’ya taşıma çalışmasının kapsamı
- Taşıma çalışması üç kola ayrılıyor
- Varlıkları içe aktarma: tile varlıklarını Godot projesine koyma işi
- Temel assembly’leri taşıma: Unity olmayan ana oyun motoru
XRL Applicationile motor tarafındakiGameManagerı taşıma işi - Render düzenini kurma: çekirdek başlatıldıktan sonra ekran çıktısını ve input’u bağlama işi
- Godot “mobile” projesi oluşturuldu ve Qud’un texture içeriği proje kök klasörüne kopyalandı
- Godot eski
.bmpdosyalarını işleyemediği için ASCII tile’ları da içeren dosyalar topluca PNG’ye dönüştürüldü - Dönüştürmeden sonra varlıklar yüklendi, ancak içe aktarma ilerleme göstergesinin belirmesi yaklaşık 30 saniye sürdü
Derleme hatalarını azaltarak çekirdek assembly’yi taşıma
XRL Applicationkopyalandıktan sonra Godot’ta C# projesi ve solution oluşturuldu; ilk durumda 5.641 hata ortaya çıktıConsoleLibveGenkitgibi genel amaçlı kütüphaneler olduğu gibi taşındı; eski sprite/atlaslama çözümü Kobold ise dosya bazında gerekli olup olmadığı kontrol edilerek içe aktarılacak şekilde ele alındıKoboldJSON, basit bir JSON serileştirme kütüphanesi olduğu için olduğu gibi taşındıColorkullanılan 85 nokta genel değiştirme ile ele alınınca hata sayısı 4.700’e düştü- Eksik olan
GeneratedCodeklasörü eklenince olay bazlı sınıf kodu üretim çıktıları dahil oldu ve hata sayısı 1.557’ye kadar azaldı- Caves of Qud, boilerplate’i fazla olan olay bazlı sınıfları kod üreterek oluşturuyor; böylece performans ve güçlü tipli bir event yüzeyi elde eden bir yapıya sahip
Unity bağımlılığı ve glue katmanını düzenleme
Embark Builderve karakter oluşturma chargen’inde çok fazla Unity UI kodu olduğu için ilk ASCII teknik doğrulamasında kaldırıldı- Console sürümü henüz yok, ancak ilk doğrulama kayıtlı oyun yükleme veya rastgele başlangıç ile test edilebiliyor
Gameklasörü çoğunlukla Unity ile oyun arasındaki glue olsa daCodeGenerationgibi glue olmayan klasörler de bulunduğundan, bunları ayrı bir root’a veyaPlatformklasörüne taşıma yönü seçildiLanguageveHistoryKitkütüphaneleri taşınınca hata sayısı 454’e kadar düştü; kusursuz olmasa da game/glue ayrımının yapılmış olması yardımcı oldu- Geriye kalan büyük hata kategorileri
CodeDom/Roslyn,PlayFab,Harmony, bazı derleyiciyle ilgili sorunlar ve oyun katmanına sızmış UnityEngine yüzeyi idi PlayFabile ilgili kod geçici olarak yorum satırına alındı ve glue modülüne çıkarılacak aday olarak bırakıldı
Unity API yedek stub’ları ve Godot C# farkları
Color32, byte tabanlı bir renk tipi olduğu için hızlıca alternatif bir implementasyon yazıldıUnityEngineReplacerklasörü oluşturuldu; Unity dokümanlarına veya kod referanslarına bakmadan, derleme hatalarına göre yalnızca gerekli yüzey uygulandıGameObjectstub’ı oluşturulunca “GameObject bilinmiyor” hataları, gerçekten gerekli alan ve metot hatalarına dönüştü; böylece oyunun kullandığı interface yüzeyi anlaşılabildiAudioSourceiçin de hata listesine bakılarak erişilen member’lar tek tek eklendi ve oyunun gerçekten kullandığı tüm AudioSource port interface’i tamamlandı- Bunun dışında ele alınan yüzeyler şunlardı
Debug.Logyerine geçen shimScreenalternatif implementasyonuIsNullOrEmptyextension method kütüphanesinin taşınmasıMathreferansları vePI/Pifarkının ele alınması- Godot’nun
X,Ybüyük harfli koordinat adları farkının ele alınması System.Drawing.Color,System.Numerics.Vector3öğelerinin IDE tarafından yanlış import edilmesi sorunlarının temizlenmesi
- Newtonsoft JSON, Visual Studio’da NuGet paketi eklenerek çözüldü; CodeDom da
CodeDomNuGet paketiyle çözüldü
Godot’ta tam başlatmaya kadar
- Hata sayısı 11’e düştüğünde kalan sorun, mod management’ın dinamik C# derlemesiyle ilgili koduydu; zorunlu değildi ama karmaşık olduğu için sona kaldı
- Ardından link aşaması ve stub field hataları ele alınarak yaklaşık 500 bin satırlık C# kod derlendi
- Sonraki adım, küçük bir renderer ve input harness’i yaparak çekirdek assembly’yi başlatmaktı; hedef, oyunu ASCII+tile modunda çalıştırılabilir hâle getirmekti
- Godot’ta boş bir scene oluşturulup temel node’a
GameManager.cseklendi;GameManager,Nodedan miras aldı ve partial kod gerektirdi - Godot’nun
_Readymetodu Unity’ninAwakeine,_Processmetodu ise Unity’ninUpdateine karşılık gelecek şekilde kullanıldı - Başlatma sürecinde load path ve mod management taşındı; type resolver’ın tipe adla ulaşamama sorunu printf yöntemiyle izlendi
- Neden dynamic assembly işleme biçimiydi
- mod assembly dynamic olduğu için main assembly kontrolünde dynamic assembly’ler hariç tutuluyordu
- Godot editor’da main game assembly de dynamic olduğundan tip arama hedeflerinin dışında kalıyordu
- Düzeltmeden sonra tam başlatma başarılı oldu ve 500kloc oyun çekirdeği frame üretip input bekler hâle geldi
- Kalan işler “just work” diye ifade edilse de gerçekte VFX, ses ve UI bağlama tarafında ciddi miktarda iş duruyor
1 yorum
Hacker News yorumları
Bu oyun neredeyse tamamen kendi motorunu kullanıyor gibi; Unity ise yalnızca donanım soyutlama katmanı ve portlama için bir iskelet olarak kullanılıyor. Bu yüzden portlama zorluğu açısından en iyi senaryolardan birine yakın görünüyor
Bu tür oyunlar şaşırtıcı derecede çok, ama elbette çoğu Unity yapımını temsil etmiyor
Arayüz yenilemesinden sonra hâlâ böyle mi bilmiyorum; öyleyse MonoGame’e portlayıp maliyetten tasarruf etmemiş olmaları bana hep garip gelmişti
Android de benzer; işletim sistemi kamera algılama ya da şifreleme gibi şeylerin yerini alan kütüphaneleri yüklemek için kullanılmaya başlanıyor, sonra bir gün işletim sisteminin aslında ince bir metal katman ve bootloader’dan ibaret olduğu fark ediliyor
https://nitter.net/unormal/status/1703163364229161236
Lanet olsun Elon. Twitter’la uğraşmak artık gerçekten sinir bozucu
Vay, gerçekten harika. Bu portlama sürecini adım adım görebilmek de güzel; harcanan sürenin de oldukça makul olmasına şaşırdım
Özel kod bu kadar fazlaysa ve editör özelliklerini daha az kullanan bir yapı varsa, motor yerine bir rendering kütüphanesi de kullanılabilir gibi
Altta bir motor olunca bunları bedavaya elde edersiniz. Unity ise buna ücret ekleyebilir
Brian’ın ne düşündüğünü merak ediyorsanız şu videoya bakabilirsiniz: https://www.youtube.com/watch?v=U03XXzcThGU
Eskiden buradan çok şey öğrenmiştim
DHH’nin son TypeScript tartışması aklıma geldi
Statik tipler olmadan böyle bir portlama yaptığınızı hayal edin: Her değişiklikte derleyip çalıştırmanız ve çökmeleri bulmanız gerekir. Böyle zamanlarda refactoring’i kolay bir dille ve iyi bir mimariyle hazırlanmış olmak gerçekten kıymetli geliyor
Twitter hesabım yok; ne oluyor?