Kafayı yiyecektim! Oyunumuzdaki tüm karakter istatistiklerini, silah değerlerini, ödül tablolarını tek bir ScriptableObject asset'inden yönetiyorduk. Mükemmel bir sistemdi. Designer arkadaşım, Unity Editor içinden tık tık değerleri değiştirip, ben de kodda SO_GameData.Insance.playerBaseDamage gibi referanslarla okuyordum. Her şey çok güzeldi... ta ki o "küçük" değişikliğe kadar.
Test build'inde herkes bir anda tanrı moduna geçmişti. Düşmanlar tek vuruşta ölüyor, oyunun challenge'ı sıfırlanmıştı. İlk başta kodda bir multiplier hatası aradım, saatlerce debug attım. StackOverflow'da bile bulamadım böyle bir saçmalık. Meğerse sorun şuradaymış: Designer, "Şu karakterin canını 100'den 120 yapayım" derken, yanlışlıkla basePlayerDamage değerini de 10'dan 1000'e çekmiş! Ve bu değişiklik, projedeki TÜM ScriptableObject instance'larını etkilemişti çünkü hepsi aynı asset'i referans alıyordu.
C#:
// İşte o lanet olası referans
public SO_GameData gameData; // Inspector'da atanıyor
float damage = gameData.basePlayerDamage; // Artık 1000!
Olayın özü şu: ScriptableObject'ler, proje içinde tek bir asset. Birisi editor'da değeri değiştirdi mi, bu değişiklik VCS'ye (Git) push ediliyor ve bir sonraki pull'da herkesin makinesine yayılıyor. "Bu değeri runtime'da değiştirebilir miyim?" sorusunun cevabı ise EVET, ama bu sefer de değişiklik kalıcı oluyor, build'ten build'e taşınıyordu!
Çözüm olarak, kritik balance datalarını runtime'da initialize ederken bir kopyasını oluşturmayı düşündüm. Yani asset'ten oku, ama hemen bir ScriptableObject.Clone veya özel bir data class'ına kopyala. Böylece designer'ın editor'da yaptığı "anlık" değişiklikler, oyunun çalışan build'ini anında mahvedemez.
Şaka gibi ama bütün bir test sürecini çöpe attıran bu basit hata, bana "convenience" ile "safety" arasındaki ince çizgiyi hatırlattı. ScriptableObject'ler harika, ama büyük takım projelerinde bir "değer değişikliği lock" mekanizması veya otomatik testler şart.
Siz bu tarz shared asset'leri nasıl yönetiyorsunuz? Designer'ların canlı datayı kazara override etmesini engellemenin temiz bir yolu var mı? Yoksa ben mi fazla paranoyak oldum?