leonscottkfm

Unreal MVP
31 May 2015
1,537
5
218
63
28
(34) İstanbul Avrupa
store.steampowered.com
Unrealin kendi Blueprintinde bunu yapan şeyler var. Ama bu macro mu? Function Library mi? Bilmiyorum.
Şöyle söyleyeyim size. Ben bir Multiplayer Ev satın alma sistemi yaptım. Ve bu sistemde aynı GTA oyunlarındaki gibi ev alabiliyorsunuz ve kurucu kim ise bilgisayarına SaveData olarak kaydoluyor. Ayrıca oyuncuların ID bilgileri de kaydoluyor. Sistem tamamen kapansa bile oyuncular çıkıp girse bile kendi evlerini görebiliyorlar. Ve kendi evlerine girebiliyorlar. Ve ben bunu olabildiğinde modular tasarladım. Yani bu sistemi alan birinin yapması gereken tek şey birkaç ActorComponenti gerekli yerlere eklemek.
Başka da bir şey yapmıyorlar. Sonra sahneye BasePropertyden yeni bir property türetip bırakıyor. Meshini seçiyor, satın alınmayı veya etkileşimi sağlayan kapı ikonunu evin istediği kısmına (genelde önüne) bırakıyor. Ardından buraya gelen oyuncu eğer eve sahip değilse, Evi Satın al diye button çıkıyor. Evi satın alırsa bu sefer de "Evi sat, Eve gir" gibi seçenekler geliyor. Bu evin sahibi olmayan diğer oyuncularda ise ev ikonu kırmızı görünüyor. Ayrıca açılan pencerede her türlü owner bilgisi ev bilgisi , ismi ,resmi,türü yazıyor.
Tüm her şey ActorComponentler ile replicated şekilde Save sistemiyle çalışmakta.

Kullanıcının sistemini bozmadan olabildiğince sadece tak çıkar mantığı yapmak istedim. Yani benim yaptığım ekosistemi kullanmasın oyununu benim ekosistemime göre tasarlamasın. Benim eko sistemimi tek tık ile kendi devasa sistemine entegre edebilsin. Çünkü biz bu adamın hangi sistemleri kullandığını ne şekilde kullandığını bilemeyiz.

Şimdi gelelim asıl probleme. Ben bu Evi alma sistemine Para olayı eklemek istiyorum. Fakat kullanıcı, para sistemini nasıl yaptı? Hangi Blueprintte yaptı? Mesel Pawn da mı yaptı? Yoksa PlayerStatede mi yaptı? Bunu ben bilemem. Ben istiyorum ki benim sisteme tek bir BP nodesi ile erişsin ve Float değerindeki parasını bağlasın. Ev alma komutu çalıştığında benim sistem o girilen değeri evin fiyatı ile karşılaştırsın eğer uygunsa evin fiyatından çıkarsın ve geri SET etsin.

Yani dışarıdan girilecek veriyi bilmiyoruz. Girdiyi alıp tekrar kendisine SET edip çıktı olarak verecek. Fakat değişkeni asla bilmiyoruz ve tamamen dışarıdan girilen bir değişken bu.
Bunu yapan bir şey vardı Soft Reference mi? Farklı bir şeydi. Bir videoda izlemiştim.

Bana bunu bilen biri varsa söylerse çok sevinirim.

EDIT: Sanırım buldum. Fonksiyonlardaki Pass-BY-Reference sistemi. Fakat RPC ağından geçemiyormuş bu sistem. Yani multiplayer için kullanışsız. Onun yerine BP_Interface yapmak daha doğru olacak sanırım. Parası neredeyse oraya implement eder.

xd.png

xd2.png
 
Son düzenleme:
Selamlar.
Anladığım kadarıyla burada aslında iki ayrı problem var.
İlk problem, Marketplace'te dağıttığın sistemin kullanıcının kendi para sistemini tanımadan onunla nasıl haberleşeceği.
Örneğin A geliştiricisi parasını PlayerState içerisinde Gold olarak tutabilir, B geliştiricisi ise ayrı bir EconomyComponent içerisinde Credits kullanabilir. Sen bunların hiçbirini önceden bilemezsin.
Bu nedenle doğrudan kullanıcının değişkenini almaya çalışmak yerine bir abstraction/interface tanımlamak daha doğru olur.

Örneğin:
BPI_CurrencyProvider
içerisinde:
CanAfford(Amount)
TrySpend(Amount)
GetBalance()


gibi fonksiyonlar olabilir.

Paketi alan geliştirici kendi para sisteminin bulunduğu Blueprint'te bu interface'i implement eder.

Senin Property sistemin de paranın hangi değişkende olduğunu bilmeden sadece:
TrySpend(HousePrice)

çağırır.

Kullanıcı ister Gold, ister Money, ister TL, ister tamamen farklı bir inventory sistemi kullansın; senin sistemin bundan bağımsız kalır.
Multiplayer tarafında satın alma isteğinin server'a gitmesi ve para kontrolü / bakiye işlemlerinin authoritative tarafta yapılması gerekir

Bunun dışında bir de kalıcılık konusu var...
Eğer para ve ev sahipliği kullanıcılar çıkıp girdikten veya server restart olduktan sonra da korunacaksa, bu bilgilerin authoritative bir persistence katmanında tutulması şart...

Basit bir projede SaveGame, JSON, SQLite gibi bir yapıyla çok kolay olabilir ama adam akıllı multiplayer yapıda MySQL/PostgreSQL gibi bir veritabanı veya ayrı bir backend servisi kullanılabilir. Ben şahsen backend servisleri için Laravel kullanıyorum.

Ufak basit bir JSON örneği mesela:
JSON:
{
"players": {
"5123": {
"money": 12500
},
"8451": {
"money": 3200
}
},

"houses": {
"1": {
"owner_player_id": 5123
},
"3": {
"owner_player_id": 8451
},
"7": {
"owner_player_id": 5123
}
}
}

Burada örneğin players.5123.money, 5123 ID'li oyuncunun parasının source-of-truth'ı olur.
houses.1.owner_player_id ise 1 numaralı evin sahibinin 5123 olduğunu belirtir

Satın alma akışı da kabaca:
Client -> Server Purchase Req. -> Currency Check -> Currency Operations -> House Ownership -> Save/Persist -> Replication
şeklinde ilerler.

Yani kısaca:
- Kullanıcının para sistemine bağlanma problemi: BPI / Adapter
- Multiplayer güvenilirliği: Server Authority
- Para ve ev sahipliğinin kalıcılığı: Persistent Storage / Database

Umarım sorunu doğru anlamışımdır.
 
  • Beğen
Tepkiler: leonscottkfm
Selamlar.
Anladığım kadarıyla burada aslında iki ayrı problem var.
İlk problem, Marketplace'te dağıttığın sistemin kullanıcının kendi para sistemini tanımadan onunla nasıl haberleşeceği.
Örneğin A geliştiricisi parasını PlayerState içerisinde Gold olarak tutabilir, B geliştiricisi ise ayrı bir EconomyComponent içerisinde Credits kullanabilir. Sen bunların hiçbirini önceden bilemezsin.
Bu nedenle doğrudan kullanıcının değişkenini almaya çalışmak yerine bir abstraction/interface tanımlamak daha doğru olur.

Örneğin:
BPI_CurrencyProvider
içerisinde:
CanAfford(Amount)
TrySpend(Amount)
GetBalance()


gibi fonksiyonlar olabilir.

Paketi alan geliştirici kendi para sisteminin bulunduğu Blueprint'te bu interface'i implement eder.

Senin Property sistemin de paranın hangi değişkende olduğunu bilmeden sadece:
TrySpend(HousePrice)

çağırır.

Kullanıcı ister Gold, ister Money, ister TL, ister tamamen farklı bir inventory sistemi kullansın; senin sistemin bundan bağımsız kalır.
Multiplayer tarafında satın alma isteğinin server'a gitmesi ve para kontrolü / bakiye işlemlerinin authoritative tarafta yapılması gerekir

Bunun dışında bir de kalıcılık konusu var...
Eğer para ve ev sahipliği kullanıcılar çıkıp girdikten veya server restart olduktan sonra da korunacaksa, bu bilgilerin authoritative bir persistence katmanında tutulması şart...

Basit bir projede SaveGame, JSON, SQLite gibi bir yapıyla çok kolay olabilir ama adam akıllı multiplayer yapıda MySQL/PostgreSQL gibi bir veritabanı veya ayrı bir backend servisi kullanılabilir. Ben şahsen backend servisleri için Laravel kullanıyorum.

Ufak basit bir JSON örneği mesela:
JSON:
{
"players": {
"5123": {
"money": 12500
},
"8451": {
"money": 3200
}
},

"houses": {
"1": {
"owner_player_id": 5123
},
"3": {
"owner_player_id": 8451
},
"7": {
"owner_player_id": 5123
}
}
}

Burada örneğin players.5123.money, 5123 ID'li oyuncunun parasının source-of-truth'ı olur.
houses.1.owner_player_id ise 1 numaralı evin sahibinin 5123 olduğunu belirtir

Satın alma akışı da kabaca:
Client -> Server Purchase Req. -> Currency Check -> Currency Operations -> House Ownership -> Save/Persist -> Replication
şeklinde ilerler.

Yani kısaca:
- Kullanıcının para sistemine bağlanma problemi: BPI / Adapter
- Multiplayer güvenilirliği: Server Authority
- Para ve ev sahipliğinin kalıcılığı: Persistent Storage / Database

Umarım sorunu doğru anlamışımdır.
Teşekkür ederim ben de sorunu Interface ile çözdüm başka yöntem yok zaten :)
Kalıcılık konusunda herhangi bir database kullanmıyorum. Bunu SaveGame ile yaptım. Kurucu kim ise yani Session-Server başlatan kişi, onun bilgisayarındaki Save dosyasına tüm bilgiler kayıt ediliyor. Aynı eski usul multiplayer oyunlar gibi mesela SA-MP.
Local olarak kayıt oluyor ve oyuncu çıkıp girse bile veri yükleniyor. Ayrıca sunucu sahibi bilgisayarını kapatıp açsa bile kayıttan geri geliyor bilgiler. Dolayısıyla ilgili oyuncular Net Unique ID ile kayıt oldukları için, Save dosyasında da yapı=NetUniqueID olduğu için veriler geri geliyor. Bu NetUniqueID ise geliştirici hangi Subsystemi kullanıyorsa o sistemin ID numarasını alıyor. Yani o sırada Steamde ise Steam64 ID alınıyor oyunculardan.
ARK Survival Evolved diye bir oyun vardı aynı yöntemi yapıyordu sanırım. Ev sunucusu session kursak bile çıkıp girdiğimizde oyun kurucusu kim ise onun bilgisayarından geri yükleniyordu harita ve yaptığımız baseler falan.
Tabi ben daha ilerisini sağlayamam. Eğer geliştirici FAB dan bu ürünü alıp bunu database şeklinde saklamak isterse biraz kurcalaması gerekir. Hizmet kiralaması gerekir. Ya da kısacası .SAV dosyasını bir yerde muhafaza etmesi gerekir. Bu yöntem de her türlü çalışacaktır. Mesela Dedicated Server kursa .Sav dosyasına erişilebilir bir şekilde yapsa bunu yine veriler yüklenecektir. Ben de zaten verileri <Map,STR> tipinde tutuyorum.

Olabildiğince kolaylaştırmaya çalıştım sistemi fakat maalesef ki para işlemleri işin içine girince BPI olayına başvurduk. Amacım, geliştirici olabildiğince kendi sistemine sadık kalsın ve bu sistemi kendi sistemine import etsin. Template gibi kullanmasın bunu. Çünkü öyle olunca mixlemek zor oluyor. Umarım satın alacak olan geliştirici BPI nasıl yöneteceğini çözebilir :) Bir döküman hazırlayacağım bir de tutorial videosu çekeceğim. Cevap için teşekkürler.