Çalışırken değiştirilebilir C ++ modülleri nasıl uygulanabilir?


39

Hızlı yineleme süreleri, bence oyun yükü özelliklerine sahip olan fantezi grafikler ve motorlardan çok, oyun geliştirmenin anahtarıdır. Birçok küçük geliştiricinin komut dosyası dillerini seçmesine şaşmamak gerek.

Unity 3D, bir oyunu duraklatmanın ve varlıkları ve kodu değiştirmenin, ardından devam etmenin ve değişikliklerin hemen etkili olmasını sağlamanın yolu bunun için kesinlikle harika. Benim sorum şu ki, C ++ oyun motorlarında benzer bir sistem uygulayan var mı?

Bazı gerçekten süper yüksek kaliteli motorların yaptığını duydum, fakat bunu evde yetiştirilen bir motorda veya oyunda yapmanın bir yolu olup olmadığını öğrenmekle daha çok ilgileniyorum.

Açıkçası, haksızlık olur ve oyun duraklatıldığında kodunuzu yeniden derleyebileceğinizi, yeniden yüklendiğini ve her koşulda veya her platformda çalıştığını hayal edemiyorum.

Fakat belki de AI programlama ve basit seviye mantık modülleri için mümkündür. Herhangi bir projede kısa (veya uzun vadede) yapmak istemişim gibi görünmüyor, ama merak ettim.

Yanıtlar:


26

Tipik C ++ kodunuzla olmasa da, kesinlikle yapılabilir; çalışma zamanında dinamik olarak bağlayıp yeniden yükleyebileceğiniz bir C tarzı kitaplık oluşturmanız gerekir. Bunu mümkün kılmak için, kütüphanenin yeniden yüklendikten sonra kütüphaneye sağlanabilecek opak bir işaretçi içindeki tüm durumu içermesi gerekir .

Timothy Farrar yaklaşımını tartışıyor:

"Geliştirme amacıyla, kod bir kütüphane olarak derlenir, küçük bir yükleyici program kütüphanenin bir kopyasını oluşturur ve programı çalıştırmak için kütüphane kopyasını yükler. Program başlangıçta tüm verileri ayırır ve herhangi bir verilere başvurmak için tek bir işaretçi kullanır. Sadece veri okumaktan başka hiçbir şey kullanmıyorum.Program çalışırken orijinal kütüphane yeniden derlenebilir, sonra bir tuşa basıldığında, program yükleyiciye geri döner ve bu tek veri göstergesine döner. Yükleyici yeni kütüphanenin bir kopyasını çıkarır. kopyayı yükler ve veri işaretçisine yeni koda geçer. Sonra motor kaldığı yerden devam eder. " ( orijinal kaynak , artık web arşivi üzerinden erişilebilir )


Aslında soruyu cevapladığınız gibi bunu Blair'in cevabına tercih ediyorum.
Jonathan Dickinson

15

Çalışırken değiştirme, ikili kodla çözülmesi çok, çok zor bir sorundur. Kodunuz ayrı dinamik bağlantı kitaplıklarına yerleştirilse bile, kodunuzun bellekteki işlevlere doğrudan bir referans olmadığından emin olmanız gerekir (işlevlerin adresi bir yeniden derleme ile değişebilir). Bu aslında sanal işlevleri kullanmamak anlamına gelir ve işlev işaretçileri kullanan herhangi bir şey bunu bir tür gönderme tablosu aracılığıyla yapar.

Kıllı, kısıtlayıcı şeyler. Hızlı yineleme gerektiren kod için bir komut dosyası dili kullanmak daha iyidir.

İşte, geçerli kod tabanımız C ++ ve Lua'nın bir karışımı. Lua da projemizin küçük bir parçası değil - neredeyse 50 / 50'lik bir bölünme. Lua'nın anında yeniden yüklemesini uyguladık, böylece kod satırını değiştirebilir, yeniden yükleyebilir ve çalışmaya devam edebilirsiniz. Aslında, oyunu yeniden başlatmadan, Lua kodunda meydana gelen çarpışma hatalarını düzeltmek için bunu yapabilirsiniz!


3
Bir diğer önemli nokta, bir sistemi komut dosyasında tutmama niyetinde olsanız bile, çok erken yinelemeyi düşünüyorsanız, Lua'da başlamak için tamamen makul olabilir, daha sonra ihtiyaç duyduğunuzda C ++ 'a gidin. Ekstra performans ve yineleme oranı yavaşladı. Buradaki bariz dezavantajı, kodu taşıma işleminin sona ermesi, ancak çoğu zaman mantığın doğru olması zor kısımdır - kod, bu kısmı çözdüğünüzde neredeyse kendini yazar.
Logan Kincaid

15

(Eğer mizahi zihinsel görüntüden başka bir şey değilse, "maymun eklemesi" veya "ördek yumruklaması" terimini bilmek isteyebilirsiniz .)

Bu bir yana: Amacınız "davranış" değişiklikleri için yineleme süresini kısaltıyorsa, sizi en çok oraya götürecek bazı yaklaşımları deneyin ve gelecekte daha fazlasını sağlamak için güzel bir şekilde birleştirin.

(Bu bir teğet biraz sönecek, ama geri döneceğine söz veriyorum!)

  • Verilerle başlayın ve küçük başlayın: sınırlardan yeniden yükleyin ("düzeyler" veya benzeri), ardından dosya değişikliği bildirimleri almak veya düzenli aralıklarla anket yapmak için işletim sistemi işlevini kullanmak için çalışın .
  • (Bonus puanları ve daha düşük yükleme süreleri için (tekrar, azalan iterasyon süresi) veri pişirme işlemine bakın .)
  • Komut dosyaları veridir ve davranışı yinelemenize izin verir. Bir betik dili kullanıyorsanız, şimdi bu betikleri yeniden yükleme, yorumlama veya derleme bildirimlerine / yeteneğine sahipsiniz. Ayrıca, çalışma süresini esnekliği için tercümanınızı oyun konsoluna, ağ soketine veya benzerlerine bağlayabilirsiniz.
  • Kod da veri olabilir : derleyiciniz bindirmeleri , paylaşılan kütüphaneleri, DLL'leri veya benzerlerini destekleyebilir. Bu nedenle, elle veya otomatik olarak bir bindirme veya DLL dosyasını kaldırmak ve yeniden yüklemek için artık "güvenli" bir zaman seçebilirsiniz. Diğer cevaplar burada ayrıntılara giriyor. Bunun bazı değişkenlerinin kriptografik imza doğrulama, NX (yürütme yok) bit veya benzeri güvenlik mekanizmaları ile karışabileceğini unutmayın .
  • Derin, sürümlü bir kaydetme / yükleme sistemi düşünün . Durumunuzu kod değişiklikleri karşısında bile sağlam bir şekilde kaydedebilir ve geri yükleyebilirseniz, oyununuzu kapatabilir ve aynı noktada yeni bir mantıkla yeniden başlatabilirsiniz. Söylemesi yapmaktan daha kolay, ancak yapılabiliyor ve talimatları değiştirmek için hafıza takmaktan çok daha kolay ve daha taşınabilir.
  • Oyununuzun yapısına ve kararlılığına bağlı olarak kayıt ve oynatma işlemlerini yapabilirsiniz . Bu kayıt sadece "oyun komutlarının" üzerindeyse (örneğin bir kart oyunu düşünün), istediğiniz tüm oluşturma kodunu değiştirebilir ve değişikliklerinizi görmek için kaydı yeniden yapabilirsiniz. Bazı oyunlar için bu, bazı başlangıç ​​parametrelerinin (örn. Rastgele bir tohum) kaydedilmesi ve daha sonra kullanıcı işlemlerinin yapılması kadar kolaydır. Bazıları için çok daha karmaşık.
  • Derleme süresini azaltmak için çaba gösterin . Yukarıda belirtilen kaydetme / yükleme veya kaydetme / oynatma sistemleriyle veya hatta bindirmeleri veya DLL'ler ile birlikte, bu işlem geri dönüşünüzü diğer tüm işlemlerden daha fazla azaltabilir.

Veri ya da kodu yeniden yüklemeyi başaramasanız bile bu noktaların çoğu yararlıdır.

Fıkraları desteklemek:

Büyük bir PC RTS'de (~ 120 kişilik ekip, çoğunlukla C ++), en az üç amaç için kullanılan inanılmaz derecede derin bir devlet tasarruf sistemi vardı:

  • "Sığ" bir tasarruf diske değil, çok oyunculu oyunların kilit adımlı simülasyonda her 10-30 karede bir CRC kalmasını sağlamak için bir CRC motoruna beslendi; bu, hiç kimsenin aldatmadığından ve birkaç kareye sonra desync hatalarını yakaladığından emin oldu
  • Çok oyunculu desync hatası oluştuğunda ve her karede ekstra derin bir tasarruf yapıldı ve tekrar CRC motoruna beslendi, ancak bu sefer CRC motoru her biri daha küçük bayt grupları için birçok CRC üretecekti. Bu şekilde, devletin tam olarak hangi kısmının son çerçevede ayrılmaya başladığını size söyleyebilir. Bunu kullanarak AMD ve Intel işlemciler arasında kötü bir "varsayılan kayan nokta modu" farkı yakaladık.
  • Normal bir derinlik tasarrufu, örneğin ünitenizin oynattığı animasyonun tam karesini kaydetmeyebilir, ancak oyun sırasında istediğiniz zaman kaydetmenize ve devam ettirmenize izin vererek tüm birimlerinizin konumunu, sağlığını vb. Alır.

O zamandan beri DS için C ++ ve Lua kart oyunlarında deterministik kayıt / oynatma kullandım. AI için tasarladığımız API'yi (C ++ tarafında) bağladık ve tüm kullanıcı ve AI eylemlerini kaydettik. Oyunda bu işlevi kullandık (oyuncuya tekrar oynatmak için), aynı zamanda sorunları teşhis etmek için de kullandık: Bir çarpışma veya garip bir davranış olduğunda, tek yapmamız gereken kaydetme dosyasını almak ve hata ayıklama yapısında oynatmaktı.

Ayrıca, bindirmeleri birkaç kereden fazla kullandım ve onu "bu dizini otomatik olarak ören ve elde tutulan içeriği yeni el cihazına yükle" sistemimizle birleştirdik. Tek yapmamız gereken, kesim ekranını / seviyesini / ne olursa olsun ve geri gelmek ve sadece yeni veriler (sprite, seviye düzeni, vb.) Yüklenmeyecek, aynı zamanda kaplamadaki herhangi yeni bir kodu da yükleyeceğiz. Maalesef, kodun özel olarak ele alındığı kopya koruması ve bilgisayar korsanlığı önleme mekanizmaları nedeniyle bu, daha yeni el bilgisayarlarında daha da zorlaşıyor. Yine de Lua senaryoları için hala yapıyoruz.

Sonuncusu ama en önemsizi: (ve çok küçük çeşitli özel durumlarda), doğrudan talimat opcodesini ekleyerek bir parça ördek delme işlemi yapabilirsiniz. Bu en iyi sonuç sabit bir platformda ve derleyicide olmanız durumunda, en iyisidir ve neredeyse elde edilemez, çok hataya açık ve hızlı bir şekilde başarabileceğiniz şeylerle sınırlı olduğundan, çoğunlukla hata ayıklama sırasında kodu yeniden yönlendirmek için kullanırım. Yine de acele, set seti mimarlığınız hakkında size çok fazla şey öğretiyor.


6

Modülleri dinamik bağlantı kitaplıkları (ya da UNIX'te paylaşılan kitaplıklar) olarak uygulayan çalışma zamanında ve modülleri dinamik olarak kitaplıktan yüklemek için dlopen () ve dlsym () kullanarak çalışma modülleri gibi bir şey yapabilirsiniz.

Windows için eşdeğerler LoadLibrary ve GetProcAddress'tir.

Bu bir C yöntemidir ve C ++ 'ı kullanarak bazı tuzakları vardır, burada bunun hakkında okuyabilirsiniz .


Bu kılavuz, çalışırken değiştirilebilir kitaplıklar oluşturmanın anahtarıdır, teşekkür ederim
JqueryToAddNumbers 16:13

4

Visual Studio C ++ kullanıyorsanız, kodunuzu belirli durumlarda duraklatabilir ve yeniden derleyebilirsiniz. Visual Studio, Düzenle ve Devam Et'i destekler . Oyuna hata ayıklayıcısına ekle, kesme noktasında durmasını sağla ve sonra kesme noktasından sonra kodu değiştir. Kaydetmeniz ve devam etmeniz gerekiyorsa, Visual Studio kodu yeniden derlemeye çalışır, çalıştırılabilir yürütülebilir dosyaya yeniden yerleştirir ve devam eder. Her şey yolunda giderse, yaptığınız değişiklik tüm bir derleme-derleme-test döngüsünü yapmak zorunda kalmadan koşu oyununa uygulanır. Bununla birlikte, aşağıdakiler çalışmayı durdurur:

  1. Geri arama işlevlerini değiştirmek düzgün çalışmaz. E&C yeni bir kod grubu ekleyerek ve çağrı tablosunu yeni bloğa işaret edecek şekilde değiştirerek çalışır. Geri aramalar ve işlev işaretçileri kullanan herhangi bir şey için, eski, değiştirilmemiş çağrıları yürütmeye devam eder. Bunu düzeltmek için statik bir işlev çağıran bir sarma geri çağırma işlevine sahip olabilirsiniz.
  2. Başlık dosyalarını değiştirmek neredeyse hiçbir zaman işe yaramayacaktır. Bu, gerçek işlev çağrılarını değiştirmek için tasarlanmıştır.
  3. Çeşitli dil yapıları gizemli bir şekilde başarısız olmasına neden olur. Kişisel deneyimlerime göre, enums gibi şeyleri önceden ilan etmek çoğu zaman bunu yapar.

Kullanıcı Arayüzü yinelemesi gibi şeylerin hızını önemli ölçüde artırmak için Düzen ve Devam'ı kullandım. Diyelim ki, iki kutunun çekiliş sırasını yanlışlıkla değiştirmiş olmanız dışında hiçbir şey görmemeniz dışında tamamen kodlanmış çalışan bir kullanıcı arayüzünüz var. 2 kod satırı canlı olarak değiştirerek, önemsiz bir UI düzeltmesini kontrol etmek için 20 dakikalık bir derleme / derleme / test döngüsü kaydedebilirsiniz.

Bu bir üretim ortamı için tam bir çözüm DEĞİLDİR ve mantığınızı olabildiğince fazla veri dosyasına taşımak ve daha sonra bu veri dosyalarını yeniden yüklenebilir hale getirmek için en iyi çözümü buldum.


hangi derleme döngüsü 20 dakika sürer? kendimi vurmayı tercih ederim
JqueryToAddNumbers

3

Diğerlerinin de dediği gibi, C ++ 'ı dinamik olarak birbirine bağlayan zor bir problem. Ancak bu çözülmüş bir problem - COM veya yıllar boyunca kendisine uygulanan pazarlama isimlerinden birini duymuş olabilirsiniz: ActiveX.

COM, geliştirici bakış açısından biraz hatalı bir isme sahiptir, çünkü işlevlerini kullanarak işlevselliklerini ortaya çıkaran C ++ bileşenlerini uygulamak çok çaba gerektirebilir (bununla birlikte ATL - ActiveX şablon kütüphanesi ile daha kolay hale getirilmiştir). Tüketici açısından kötü bir isme sahiptir, çünkü onu kullanan uygulamalar, örneğin bir Word belgesine bir Excel elektronik tablosu veya bir Excel elektronik tablosundaki bir Visio diyagramı yerleştirmek için, gün içinde oldukça fazla çökme eğilimindeydi. Bu da aynı sorunlara yol açıyor - Microsoft'un sunduğu tüm rehberlikle bile COM / ActiveX / OLE'nin doğru olması zordu.

COM teknolojisinin kendisinin doğasında kötü olmadığını vurgulayacağım. Her şeyden önce DirectX, işlevlerini ortaya çıkarmak için COM arabirimlerini kullanır ve ActiveX denetimini kullanarak Internet Explorer'ı yerleştiren çok sayıda uygulamada olduğu gibi yeterli çalışır. İkincisi, C ++ kodunu dinamik olarak birbirine bağlamanın en basit yollarından biridir - bir COM arayüzü aslında sadece saf bir sanal sınıftır. CORBA gibi bir IDL'si olmasına rağmen, özellikle tanımladığınız arayüzler sadece projenizde kullanılıyorsa, onu kullanmak zorunda değilsiniz.

Windows için yazmıyorsanız, COM'un değerlendirmeye değer olmadığını düşünmeyin. Mozilla, kod tabanlarında (Firefox tarayıcısında kullanılan) yeniden uyguladı, çünkü C ++ kodlarını birleştirecek bir yola ihtiyaçları vardı.


2

Burada oyun kodu için C ++ derlenmiş bir uygulama var . Ayrıca, aynı şeyi yapan en az bir tane özel oyun motoru olduğunu da biliyorum. Zor, ama yapılabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.