Saatlik oyun sunucuları. Sadece oynarken öde.

Yalnızca Windows'a özgü bir oyun sunucusu Linux'ta nasıl çalıştırılır

Bazı Steam oyunları yalnızca Windows dedicated sunucusu getirir. Depoda Linux binary'si yoktur, bu yüzden alışılmış tavsiye "onu bir Windows makinesinde çalıştır" olur. Buna mecbur değilsin. Wine ile Windows sunucusunu normal bir Linux makinede çalıştırabilirsin ve Steam'e bağlanıp gerçek oyuncuları kabul eder. Bu, bizde işe yarayan tam tarif, örnek olarak Alien Swarm: Reactive Drop (ücretsiz bir Source co-op oyunu) ile. Aynı yaklaşım diğer yalnızca Windows Source dedicated sunucularına da taşınmalı.

Önce, gerçekten Linux sunucusu olmadığını doğrula

Varsayma. Wine'a uzanmadan önce doğrudan Steam'e sor. steamcmd'yi app'e yönlendir ve platform listesini oku:

steamcmd +login anonymous +app_info_print <appid> +quit \
  | grep -iE "oslist|name"

Eğer dedicated sunucu app'i yalnızca "oslist windows" ise, geri dönülecek native Linux build'i yoktur. Bir Linux kurulumunu zorlamayı da deneyebilirsin; gerçekten hiç Linux deposu yoksa hızlıca başarısız olur:

steamcmd +@sSteamCmdForcePlatformType linux \
  +login anonymous +app_update <appid> validate +quit
# ERROR! Failed to install app '<appid>' (Missing configuration)

O hata ve hiç ELF dosyasının inmemesi bunu doğrular. Artık yol Wine. Sunucuyu VE app 1007'yi (Steamworks Common Redistributables) aynı klasöre, windows platform tipiyle kur. App 1007, sunucunun ihtiyaç duyduğu Steam DLL'lerini getirir ve nedenini Adım 2'de göreceksin:

steamcmd +@sSteamCmdForcePlatformType windows +login anonymous \
  +force_install_dir /path/to/server \
  +app_update <appid> validate \
  +app_update 1007 validate \
  +quit

Sunucu ayrıca Wine prefix'i içinde Microsoft Visual C++ 2019 runtime'ına ihtiyaç duyar. winetricks ile bir kez kurun (bir ekran gerektirir, bu yüzden xvfb-run ile sarın):

WINEPREFIX=/wine xvfb-run -a winetricks -q vcrun2019
wineserver -w

Naif Wine denemesi neden başarısız olur

Sunucuyu doğrudan Wine'dan çalıştırmak arka arkaya iki duvara toslar:

  • Konsol yok: sunucu gerçek bir terminal bekler. /dev/null'dan pipe yapmak CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents verir ve asla başlamaz.
  • Steam kütüphanesi yüklenemiyor: açılsa bile "Unable to load Steam support library" yazar ve Steam'e asla kayıt olmaz, dolayısıyla kimse onu bulamaz veya katılamaz.

İkisi de düzeltilebilir. İşte tam tarif.

Adım 1: ona gerçek bir terminal (PTY) ver

Ekransız bir makinede terminal yoktur ve Windows konsol sunucusu terminalsiz çalışmayı reddeder. Girişi açık kalan bir sözde terminale (PTY) ihtiyaç duyar, docker run -it'in size verdiği de budur. Yaygın öneri başlatmayı script ile sarmaktır. Terminalsiz bir makinede hata tam olarak budur: script'in kendi girişi dosya sonuna ulaşır, sunucunun konsol okuması da bunu görür ve ana döngüsü takılır. Harita yüklenebilir, ama sunucu soketlerinde asla yanıt vermez. Bunun yerine onu PTY açıp asla kapatmayan küçük bir Python sarmalayıcıdan başlatın ve sahte ekran için Xvfb kullanın:

Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99 WINEPREFIX=/wine

cat > launch_pty.py <<'EOF'
import os, sys
cmd = ["wine", "srcds_console.exe", "-console", "-condebug",
       "-game", "<gamedir>", "+map", "<map>", "-port", "27015"]
pid, master = os.forkpty()
if pid == 0:
    os.execvp(cmd[0], cmd)
# Parent: never close master, so the server's input stays open.
# Copy the server output to our own stdout.
while True:
    try:
        data = os.read(master, 4096)
    except OSError:
        break
    if not data:
        break
    sys.stdout.buffer.write(data)
    sys.stdout.flush()
_, status = os.waitpid(pid, 0)
sys.exit(os.waitstatus_to_exitcode(status))
EOF
python3 launch_pty.py

Bu tek başına sunucunun bir harita yüklemesini ve oyun portunu bağlamasını sağlar. Ama hâlâ Steam ile konuşamaz.

Adım 2: iki Steam DLL'i, iki farklı kaynak

Source engine, sunucu exe'sinin yanında HEM steamclient.dll HEM de steam.dll'i ister ve bize fazladan bir tur hata ayıklamaya mal olan tuzak şu: bunlar FARKLI yerlerden gelir ve app 1007 sana yalnızca BİRİNİ verir.

  • steamclient.dll: Adım 1'de kurduğun app 1007'den (Steamworks Common Redistributables) gelir. Kanonik, sürümü eşleşmiş, Valve tarafından bakımı yapılan.
  • steam.dll: app 1007'de YOKTUR. Steam İSTEMCİSİNİN bir parçasıdır ve onu almanın tek temiz yolu, Windows steamcmd.exe'yi Wine altında bir kez çalıştırmaktır; kendini günceller ve steam.dll'i (artı steamclient.dll'i) kendi klasörüne bırakır.

O yüzden steam.dll'i Wine altında steamcmd.exe ile bootstrap et, sonra iki DLL'i de sunucu exe'sinin yanına kopyala:

# steam.dll: run Windows steamcmd once under Wine (needs Xvfb for a display)
cd "$WINEPREFIX/drive_c/steamcmd"
curl -fsSLO https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip
unzip -o steamcmd.zip
DISPLAY=:99 wine steamcmd.exe +quit    # lays down steam.dll + steamclient.dll

# place both next to the server exe
cd /path/to/server
cp "$WINEPREFIX/drive_c/steamcmd/steam.dll" .
[ -f steamclient.dll ] || cp "$WINEPREFIX/drive_c/steamcmd/steamclient.dll" .

Adım 3: neden steam.dll önemli olan parça

Bu, neredeyse kimsenin yazmadığı kısım. Hata "Unable to load Steam support library" der ve kastettiği support kütüphanesi steamclient.dll değil, steam.dll'dir. Source engine, tüm Steam zincirini başlatmak için steam.dll'yi kendi çalıştırılabilir dosyasının yanında arar. Yalnızca steamclient.dll varken (ki app 1007'nin sana verdiği tek şey budur) hâlâ başarısız olur; steam.dll .exe'nin yanında olduğu an, log başarısızlıktan başarıya döner:

Connection to Steam servers successful.
VAC secure mode is activated.

VAC, sunucu düzgün giriş yapmış bir gameserver olmadıkça etkinleşmez, yani o satır kayıt olduğunun kanıtıdır. Çoğu Source sunucusu burada anonim olarak giriş yapar ve bir Game Server Login Token (GSLT) gerektirmez. Yalnızca birkaç oyun (CS2 gibi) bir tane gerektirir.

Tuzak: A2S susar

İşte bize en çok zaman kaybettiren tuzak. script sarmalayıcısıyla sunucu, araçların bir sunucunun adını, haritasını ve oyuncu sayısını okumak için kullandığı UDP sorgusu A2S_INFO'ya yanıt vermedi. Aynı makineden bile her sorgu zaman aşımına uğradı, sunucu tamamen ölü görünüyordu. Önce Wine'ı suçladık. Sorun 1. Adım'daki takılan ana döngüydü: sunucu soketlerini hiç okumuyordu.

PTY açık tutulduğunda sunucu A2S'ye normal yanıt verir ve gerçek oyuncular katılabilir. Son test yine de bir sorgunun yanıtlanması değil, bir istemcinin bağlanmasıdır. PTY doğru olunca gerçek bir oyuncu bağlandı ve oynadı:

Client "player" connected (10.0.0.5:27005).
1/ 8 on map <mapname>

Pratik ders: Wine'da barındırılan bir sunucu haritasını yüklüyor ama A2S sessizse, önce Wine'ı suçlamayın. Konsolun nasıl bağlandığını kontrol edin. Bağlı bir UDP portu sunucunun canlı olduğunun kanıtı değildir, çünkü takılmış bir sunucu paketler okunmadan birikirken portunu bağlı tutar.

Bu her Windows oyunu için çalışır mı?

Kapsam konusunda dürüst olalım. Bunu bir Source motoru sunucusunda kanıtladık ve aynı tarif (PTY, steamcmd ile kurulmuş runtime, exe'nin yanında steam.dll) yalnızca Windows'ta çalışan diğer Source dedicated sunucularında da çalışmalı. Diğer motorlardaki oyunlar Steam'i farklı entegre eder, onları ayrı deneyler olarak ele alın. Her durumda beklenecek bir şey: açılışlar yerel Linux'tan yavaştır (Wine artı steamcmd adımı artı Steam girişi).

Ya da tüm bunları atla

Bu, bir öğleden sonrayı yiyip bitiren türden bir uğraş. Sadece sunucuyu istiyorsanız, Linux filosunu ve Wine tesisatını sizin için saatlik olarak, ilk dakikadan genel bir IP ile çalıştırıyoruz. Alien Swarm: Reactive Drop henüz genel deploy sayfalarımızda değil, ama yalnızca Windows'ta çalışan diğer sunucular var, örneğin Wreckfest ve rFactor 2. 2hours.gg üzerinde neler sunduğumuza bak.

Ayrıca bak

← Tüm rehberlere dön