Geliştirici Günlükleri

MKA Engine'i geliştirirken tuttuğumuz günlükler: neyi neden böyle kurduğumuz ve ne ölçtüğümüz.

MKA Engine'i geliştirirken tuttuğumuz günlükler. Her günlükte bir kararı, nedenini ve ölçtüğümüz sonucu yazıyoruz. Motorun kendisi için MKA Engine sayfasına bakın.

Geliştirici Günlükleri

Geliştirici Günlüğü #34: Betik dilini kaldırdık, kurallar Rust'ta yazılıyor

· Ayrı sayfada aç

Ölçeksiz, kavramsal bir çizim: masada açık bir defter, yanında düz kâğıtlar ve küçük bir pirinç anahtar; arka planda bulanık bir atölye tezgâhı. Çizimde sayı, oran ya da ölçek bilgisi yoktur.

Kısaca: MKA Engine'de kuralları yazmak için kullandığımız küçük bir betik dili, yani ayrı bir yardımcı dil, 2–3 Kasım 2026'da on yedi adımda kaldırıldı. İçerik dosyalarında artık tanımlar, başlangıç verileri ve metin çevirileri duruyor; kurallar ise Rust ile yazılıyor. Rust, motorun kendisinin de yazıldığı genel amaçlı bir programlama dili. Son kayıttaki kapanış sınamaları geçti, ama bu, oyundaki her kuralın yeni biçimde doğru çalıştığı anlamına gelmiyor. Bedeli var: eski betik diliyle yazılmış modlar bu sürümde çalışmaz ve kural yazan her mod artık derlenmek zorunda.

Bir ikinci dil neden fazlaydı?

Bir oyunun kural kitabı iki ayrı dilde yazılmış olsaydı, hem yazarın hem okuyucunun iki dili birden bilmesi gerekirdi. Bizde durum buna yakındı. Motorun içinde, bir olayın ne zaman seçileceğini ve seçildiğinde ne yapacağını yazmak için küçük bir dil vardı. İçerik yazarı bu dilde bir koşul yazabilir, bir etkiyi sıraya koyabilir ya da bir yapay zekâ seçeneğinin ağırlığını belirleyebilirdi. Dilin kendi okuyucusu, kendi hata iletileri ve kendi derleyicisi vardı.

Zamanla bu dil gereksiz bir ikinci dile dönüştü. Karar sahibinin değerlendirmesi de bu yöndeydi: ihtiyaç duyulandan fazla bir alt dil oluşturmuştuk. Tasarım belgesi 2 Kasım'da yazılırken bunun yerine tek bir yol önerdi: kurallar Rust ile yazılacak, oyun da modlar da aynı dili kullanacaktı. Belgenin başındaki karar notu da açıktı: karar sahibindeydi ve içerik dilinden yalnız veri biçimi kalacaktı. Rust'ı neden seçtiğimizi ayrı bir günlükte anlattık: Geliştirici Günlüğü #0.

Dil motorun neresindeydi?

Dil yalnız içerik dosyalarında kullanılmıyordu. Yapay zekâ kararları, olay sistemi, veraset yasası, çarpanlar, görüş ve yetki kuralları ile başlangıç tarihli geçmiş etkileri de dilden besleniyordu. Dilin çevresinde editörlere yardım eden bir dil sunucusu ile dilin belgelerini döken araçlar da vardı. Dil, bir veri biçiminin parçası olmanın ötesine geçip motorun iç mantığına yayılmıştı. Bu yüzden söküm tek bir dosyayı silmekten ibaret değildi; motorun birçok parçasına geniş biçimde dokunuyordu.

Tasarım belgesinin 2 Kasım'daki ölçümüne göre ilk oyun içeriğimiz 15 dosya ve 53.267 satırdı. Kural taşıyan tek dosya vardı: içinde bir vergi karar grubu (4 seçenek) ve bir para karar grubu (3 seçenek) bulunuyordu. Tasarım belgesi bu yedi seçeneğin her birinin koşulunu ve ağırlığını ayrı birer Rust işlevi olarak yazmayı planlıyordu.

Neler kaldı, neler gitti?

Kalan şey veri biçimiydi: tanımlar, başlangıç verileri, metin çevirileri ve mod veri yamaları. Olayların başlık ve seçenek metinleri de çevirileriyle birlikte veri dosyalarında kalıyor. Hangi olayın, hangi karar grubunun ya da hangi başlangıç değerinin var olduğunu yazan düz dosyalar yerinde duruyor.

Giden, bu verinin içine gömülü küçük programlardı: koşul dili, etki dili, sayı hesaplarını yazan formül dili, bu hesapları çalıştırılabilir koda çeviren araç ve değerlendirme bağlamları. Koşulun ne anlama geldiğini yazıya döken ve etkinin önizlemesini gösteren katman, "ya olsaydı" sorguları ve konsoldan betik denemek de gitti. Yapay zekânın motor içindeki strateji, kişilik, plan, bilgi, bütçe ve askerî katmanları da gitti. Bunlar formül ve koşullarla yazılmış strateji içeriğiydi; bundan sonra strateji, oyunun kendi Rust kodunda yazılacak.

Olay sistemi kaldı. Bir olayın takvimde ne zaman seçileceğini ve seçim süresini yöneten düzenek motorda duruyor; kalkan, olayın koşulunu ve etkisini yazan dildi. Karar gruplarında da düşünme sıklığı, işin dilimlere bölünmesi, gecikme ve adım başına iş sınırı motorda kaldı. Yalnızca seçeneklerin koşulu ve ağırlığı Rust işlevi oldu.

Kayıt dosyasının biçimi değişmedi; olay takvimi ve yapay zekânın bekleyen karar satırları da aynı kaldı. Ancak içerik şeması değiştiği için, tasarım belgesine göre bu sürümden önceki kayıtlar reddedilir.

Ölçeksiz, şematik bir çizim. Solda bir veri dosyasının içinde küçük bir kural dili, yanında onu çalıştıran ayrı bir katman; sağda yalnız veri içeren dosyalar ve her kuralın adını taşıyıp Rust'ta yazılmış işlevlere bağlanan bir kutu. Çizimde sayı, oran ya da ölçek yoktur.

Bir kural artık nasıl yazılıyor?

Veri dosyası hangi seçeneğin var olduğunu, hangi metinle görüneceğini ve hangi sayılarla çalışacağını söyler. Seçeneğin uygun olup olmadığını ve ne kadar ağırlıklı olduğunu ise dosyada adı yazılan bir Rust işlevi belirler.

Tasarım belgesinin ortak kuralı şöyle: veri neyin var olduğunu ve hangi sayılarla çalıştığını söyler; Rust ise bunun neye göre geçerli olduğunu. Rust tarafındaki işlevler iki türdedir. Koşul ve ağırlık işlevleri yalnızca okur; dünyada değişiklik yapmaz, rastgele bir çekiliş de yapmazlar. Etkiler ise dünyayı değiştirebilir: yeni bir kayıt oluşturabilir, bir kaydı silebilir ya da bir olay tetikleyebilir. Bir etki hatasız biterse yazdıkları uygulanır.

Eskiden bir seçeneğin koşulu ve ağırlığı, dosyanın içinde dilde yazılmış kısa ifadelerdi. Şimdi veri dosyası yalnızca "bu seçeneğin ağırlığı şu adlı işlevdir" der. İşlevin kendisi Rust'ta yazılır, derlenir ve oyuna eklenir.

Bir mod, kendisinden önce yüklenen modların işlevlerini adıyla çağırabilir; ama çağrılar birbirine dönerek döngü oluşturamaz. Çarpanların koşulu da aynı yoldan geçer: içerikte adı yazılan bir işlev karar verir.

Bilinmeyen bir ad yazılırsa yükleme durur. Hata, dosya, satır ve sütun bilgisiyle gösterilir; proje bu haliyle yüklenmez, yani oyun bu içerikle açılmaz. Hata, oyun başlamadan içerik yazarının önüne çıkar. Aynı denetim yapay zekâ karar seçeneklerinde, veraset yasasında ve çarpan koşullarında da geçerli.

Ölçeksiz, şematik bir akış. Veri dosyası kuralın adını yazar; yükleme sırasında ad doğrulanır ve tanımlı bir işlevle eşleşir. Eşleşmezse dosya, satır ve sütun bilgisiyle hata verilir; eşleşirse işlev, kural gerektiğinde değerlendirilir. Kutular sayı ya da oran göstermez.

Modlar için ne değişti?

Mod yazanlar için en büyük değişiklik, kuralın artık Rust'ta yazılması. Eski betik diliyle yazılmış modlar bu sürümde çalışmaz; geriye uyumluluk tutulmadı. Bu, mod yazarları için somut bir bedel.

Tasarım belgesi, Paradox tarzı modlamanın büyük kısmı için bunun ne anlama geldiğini açıkça yazıyor. Bir olayın koşuluna satır eklemek gibi bir iş artık işlevin tamamını yeniden yazmak demek. Yeni düzende olayın koşul alanını kendi işlevinize yönlendirirsiniz ve bu işlev koşulun tamamını yeniden yazar. Tasarım bunu bilinçli bir seçim olarak nitelendiriyor: mod yazmanın eşiği yükseliyor. Kılavuzun bu bedeli açıkça söylemesi gerektiği de belgede yazılı.

Bir mod, önceden yüklenmiş modların sistemlerini değiştirebilir ya da kapatabilir; bu, oyunun bağladığı motor sistemleri için de geçerlidir. Eylem zincirleri kalktı. Ayın başında ya da başka bir zamanda yapılacak iş, o zamana bağlanan bir Rust kodu olarak yazılır; birden fazla mod aynı ana bağlanabilir ve bunlar mod yükleme sırasıyla çalışır.

Kural yazan her mod derlenmek zorundadır. Yalnızca sayı, ad, metin çevirisi ve içerik kayıtlarını değiştiren mod derleme gerektirmez. Konsoldan betik denemek, koşulların ne anlama geldiğini yazıya döken açıklamalar ve etki önizlemeleri de kalktı. İpucu metinlerini isteyen oyun, bunları kendi işleviyle üretebilir. Mod arayüzü söküm sırasında değişti.

Kazanç da var. Oyun ve modlar aynı dilde, Rust'ta yazılıyor. Bilinmeyen bir ad, yükleme sırasında dosya ve satır bilgisiyle hata olarak görünüyor. Olay takvimi motorda kaldığı için her modun takvimi baştan yazması gerekmiyor.

Sıra neden önemliydi?

Bir binanın duvarını kaldırmadan önce, o duvara dayanan tavanın nerede durduğunu bilmek gerekir. Söküm de böyle ilerledi. Tasarım belgesi her adımı tek bir alt sistem olarak tanımladı ve her adımdan sonra motorun derlenmesini ve o adımın sınamalarının geçmesini istedi.

Sıra da bağımlılıklara göre kuruldu. Tasarım belgesinde içerik testleri ikinci adım olarak geçiyor; ama bu adım on üçüncü adımdan sonra yapıldı, çünkü testlerin sınadığı veraset ve koşul özellikleri ancak dokuzuncu ve on üçüncü adımlarda kaldırıldı. Bir parçayı kaldırmadan önce onu kullanan her yeri bulmak gerekiyordu; sıra bunu zorunlu kıldı. Bir de başka işlerle çakışmamak için tasarım, adımların sırayla ve tek tek kaydedilmesini istedi.

Söküm nasıl ilerledi?

Söküm 2 Kasım'da başladı ve 3 Kasım'da bitti. On yedi adımın beşi 2 Kasım'da, kalan on ikisi 3 Kasım'da kaydedildi; son kayıt 3 Kasım öğleden sonra alındı. Adımlar dört başlıkta toplanabilir:

BaşlıkNe kaldırıldı ya da taşındı
Geliştirici araçlarıKonsoldan betik denemek, koşul açıklamaları, etki önizlemeleri, editörlerdeki anahtar sözcük yardımı ve betik maliyet uyarıları
Kuralların işlevlere taşınmasıEtkiler Rust'a geçti; modlar birbirinin işlevlerini çağırabilir oldu ve sistem değiştirme ya da kapatma geldi; olaylar işlev adlarıyla bağlandı ve olay eylemleri kalktı; yapay zekâ karar seçenekleri, veraset yasası ve çarpan koşulu işlevlere geçti
Kural dilinin çekirdeğiKoşul dili, etki dili, formül dili ve değerlendirme bağlamları kaldırıldı; döngü, liste taraması ve iç içe eylem sınırları proje ayarlarından çıktı
Testler ve belgelerBetik temelli içerik testleri kalktı; yerlerini alacak Rust testlerinin tamamlandığı bu yazıda iddia edilmiyor; içerik kılavuzu veri biçimini anlatacak şekilde yeniden yazıldı
Söküm adımlarının dört başlığı
Ölçeksiz, şematik bir pano. Söküm adımlarının dört başlığı dört çerçevede, her birinde bir simgeyle gösterilir: alet kutusu, belgeden dişliye ok, düğümlü kurdeleler ve onay kutusu ile kitap. Çerçeveler yalnız dört grubu ayırır; adım sayısı, oran ya da ölçek gösterilmez.

Kapanış kaydı ne gösteriyor?

Son kayıtta, yani 3 Kasım öğleden sonra alınan kayıtta, kod denetim aracı uyarı vermedi ve çalışma alanı sınamalarında başarısız kalan olmadı. Motor üç derleme hedefinde de sınamalarını geçti: iki işlemci mimarisinde ve taşınabilir bir çalıştırma biçiminde. Bağımlılık denetimi de geçti. Kayıt, bazı sınamaların atlandığını da yazıyor.

Bu, motorun bu hedeflerde derlenip sınamalarını geçtiğini gösteriyor. Ama bazı şeyleri göstermiyor. Her adımın kendi sınamasının geçtiğini bu yazıda tek tek denetlemedik; yazı, son kayıtta alınan sonuçlara dayanıyor. Kuralların çalışma hızını ölçmedik; yeni işlevlerin eskisinden hızlı ya da yavaş olduğunu söylemiyoruz. Tasarım belgesi de çağrı maliyetinin ölçülmediğini açıkça yazıyor. Bazı motor sınamaları oyun verisi yerine yapay bir harita dünyası kullanıyor; bu yüzden bu sonuçlar tek başına oyundaki her kuralın doğru çalıştığını göstermez. Oyunun kendi içerik denetimleri de bu yazının kapsamında değil.

Tasarım, olay, yapay zekâ ve veraset testlerinin Rust'ta yeniden yazılmasını öngörüyordu. Bu yazı, o yeniden yazımın tamamlandığını iddia etmiyor.

Döngü ve liste sınırlarına ne oldu?

Bir masa oyununda bir kural, tur uzasa da kendi kendine çoğalmaz. Bilgisayarda ise bir kural döngüye girerse oyun adımı uzayabilir. Önceki günlüğümüzde (#13) anlattığımız döngü ve liste tarama sınırları bu yüzden vardı. Bu sınırlar artık proje ayarlarında yok. Ayarlarda yalnızca modların işlem ve bellek sınırları kaldı; döngü, liste taraması ya da iç içe eylem için bir ayar yazılırsa yükleme hata verir.

Olay koşulları ve karar ağırlıkları artık her değerlendirmede bir işlev çağrısı oluyor. Tasarım belgesi, bu çağrıların da modun işlem sayımına dahil olduğunu yazıyor. Yani sınır tamamen kalkmadı: döngü ve liste sayaçları gitti, ama mod işlem ve bellek sınırları ile çağrıların işlem sayımı kaldı.

Bu yazı, döngü ve liste sınırlarının yerine geçen ayrı bir sayma düzenini anlatmıyor. İşlem sayımı aşıldığında ne olacağı da bu yazının konusu değil.

Tasarımda kapanan açık sorular

Tasarım belgesinde açık kalan yedi soru vardı. 2 Kasım'da her biri geliştirme tarafında karara bağlandı. Okuyucu ve mod yazarı için önemli olanlar şunlar:

  • Bir mod, kendisinden önce yüklenen modların işlevlerini adıyla çağırabilir; çağrı döngüsü oluşamaz.
  • Sistem değiştirme ya da kapatma, önce yüklenmiş modların sistemlerini ve oyunun bağladığı motor sistemlerini kapsar.
  • Veraset yasasında kuşak farkını işlev kendisi hesaplar; bu karar mod arayüzünü değiştirmedi.
  • Kayıt yükseltme özelliği kalır. Bu, oyunların kendi kayıtlarını yeni sürümlere taşıması içindir; eski kodla uyumluluk değildir.
  • İçerik yazarlarının kılavuzu veri biçimine göre yeniden yazıldı; betik anlatımı çıkarıldı.

Yapay zekâ neyi görebilir?

Kapalı kartlarla oynanan bir oyunda rakip elinizdeki kartları göremez. Bilgisayar oyununda bu kural kodla korunmak zorundadır. Eski sistemde, yapay zekâ formüllerinin neyi okuyabileceğini sınırlayan bir koruma katmanı vardı. Bu katman kalktı. Karar ağırlığını hesaplayan Rust işlevi artık oyunun durum verisini doğrudan okuyabiliyor. Sisli bir oyunda neyin görüleceğini korumak, bu yüzden oyunun kendi kodunun işi oldu.

Tasarım belgesi bunu açık bir risk olarak yazıyor. Belgenin sekizinci adım notu, bir sınama senaryosunda yapay zekânın görmediği bir hedefi seçmediğini kaydediyor. Bu tek bir senaryo; genel bir garanti değil. Gerekirse motor, gözlemcinin gördüğünü okuyan ayrı bir düzen ekleyebilir; bu ayrı bir motor işi olur.

Henüz ölçülmeyenler ve açık işler

Üç iş açık kaldı. Birincisi, çağrı maliyeti ölçülmedi; yeni kuralların hızı hakkında veri yok. Tasarım, gerekirse bir sahibin bütün seçeneklerini tek çağrıda değerlendiren toplu bir çağrının eklenebileceğini yazıyor. İkincisi, yapay zekânın görmemesi gereken bilgiyi korumak oyunun kodunun işi; motor tarafında gerekirse ayrı bir iş olarak ele alınacak. Üçüncüsü, oyunun kendi içeriğinin yeni biçimde derlenmesi ve denetlenmesi bu yazının kapsamında değil; tasarıma göre bu kontroller oyun tarafında, oyun oturumunda yapılacak.

Bu yazı neyi söylemiyor?

Bu yazı, motorun kural dilini kaldırma işini, kapanış sınamalarını ve tasarım kararlarını anlatıyor. Oyundaki her kuralın yeni biçimde çalıştığını, yeni kuralların hızını, bir modun yeni sürümde nasıl davranacağını ya da oyuncunun oyunda ne fark edeceğini ölçmedik. Bunlar ayrı bir değerlendirme gerektiriyor.

Sık sorulanlar

Eski betik diliyle yazılmış modlar çalışacak mı?

Bu sürümde hayır; geriye uyumluluk tutulmadı. Bu modların kuralları Rust işlevleri olarak yeniden yazılmalı. Tanımlar, başlangıç verileri, metin çevirileri ve veri yamaları ise veri olarak kalıyor.

Kural yazmak için ne gerekiyor?

Bir Rust işlevi, o işlevin derlenmesi ve veri dosyasında işlevin adı. Veri dosyaları veri olarak kalıyor ve yalnızca işlevin adını taşıyor.

Bir mod, başka bir modun işlevini kullanabilir mi?

Evet, ama yalnızca kendisinden önce yüklenen modların işlevlerini adıyla çağırabilir. Sonradan yüklenen bir modun işlevini çağıramaz; bu yüzden çağrı döngüsü oluşmaz.

Eski kayıtlarım açılacak mı?

Kayıt dosyasının biçimi değişmedi. Ancak içerik şeması değiştiği için, tasarım belgesine göre bu sürümden önceki kayıtlar reddedilir. Eski bir kayıtla bu durum sınanmadı.

Oyun daha hızlı mı oldu?

Bu yazı bunu ölçmedi. Kural çağrılarının maliyeti tasarımda da ölçülmemiş olarak geçiyor, bu yüzden hız hakkında bir iddiamız yok.

Olay sistemi de kalktı mı?

Hayır. Olayların takvimde ne zaman seçileceğini yöneten düzenek motorda kaldı; kalkan, olayın koşulunu ve etkisini yazan betik diliydi.

Kaynaklar ve bağlantılar