· Hasan Alp Güngör
CS2 için Major tarzı canlı yayın arayüzü: Game State Integration ile
Counter-Strike 2'nin Game State Integration özelliğiyle maç verisini nasıl aldığımı, Python sunucusunu ve oyunun vermediği killfeed'i nasıl çıkardığımı anlatıyorum.
- Python
- Flask
- JavaScript
- CS2

Major turnuvalarını izlerken ekrandaki yayın arayüzü hep ilgimi çekti: oyuncuların canı, parası, silahları, killfeed, bomba sayacı. Bunun benzerini kendi maçlarım için yapmak istedim.
Oyundan veri almak
CS2'nin Game State Integration (GSI) diye bir özelliği var. Oyunun cfg klasörüne bir dosya koyuyorsun, oyun da maç sırasında istediğin verileri JSON olarak verdiğin adrese gönderiyor. Benim dosyamda verinin her 0,1 saniyede bir yerel sunucuma gönderilmesini istiyorum:
cfg"Manyaksisko35 GSI v1"
{
"uri" "http://127.0.0.1:3000"
"throttle" "0.1"
"data"
{
"map" "1"
"round" "1"
"player_state" "1"
"allplayers_state" "1"
"allplayers_weapons" "1"
"allplayers_match_stats" "1"
"phase_countdowns" "1"
}
}Arada bir Python sunucusu
Oyunun gönderdiği JSON çok büyük ve dağınık. Python ile yazdığım küçük bir Flask sunucusu bu veriyi alıp sadeleştiriyor: skorlar, raunt, bomba durumu, kalan süre ve her oyuncu için isim, can, para, ana silah, el bombaları ve K/D. Ana silahı bulurken bıçağı, C4'ü ve tabancayı atlıyorum; oyuncunun ana silahı yoksa tabancasını gösteriyorum. Arayüz bu sade veriyi ayrı bir adresten çekiyor.
Titremeyen bir arayüz
Arayüz HTML, CSS ve JavaScript. Sunucudan saniyede 10 kez veri çekiyor. İlk denemede her seferinde bütün paneli yeniden çiziyordum ve yayında titriyordu. Şimdi her alanı sadece değeri gerçekten değiştiyse güncelliyorum; can barları da CSS geçişiyle yumuşakça kayıyor.
Oyunun vermediği killfeed
GSI kimin kimi vurduğunu doğrudan söylemiyor. Ben de her güncellemede oyuncuların kill ve ölüm sayılarını bir önceki durumla karşılaştırıyorum. Kill sayısı artanlar katil, ölüm sayısı artanlar kurban oluyor; ikisini eşleştirip killfeed'e silah ikonuyla ekliyorum. Satırlar beş saniye sonra kayboluyor.
jsplayers.forEach((p) => {
const before = previous[p.name];
if (before && p.kills > before.kills) killers.push(p);
if (before && p.deaths > before.deaths) victims.push(p);
});
for (let i = 0; i < Math.max(killers.length, victims.length); i++) {
addKillItem(killers[i], victims[i]);
}Bomba sayacı
Bomba kurulunca normal raunt süresi kayboluyor ve yerine 40 saniyelik kırmızı bir bomba çubuğu geliyor. Imha başlayınca çubuk beyaza dönüyor. Oyun imha süresini doğrudan vermediği için kalan süreye bakıyorum: 5,5 saniyeden azsa oyuncunun kiti var demektir ve çubuğu 5 saniyeye göre, yoksa 10 saniyeye göre dolduruyorum.
Projenin kodu GitHub'da açık ve yapılışını YouTube kanalımda da anlattım.

