Niektóre gry na Steam dostarczają serwer dedykowany tylko na Windows. W depocie nie ma binarki na Linuksa, więc zwykła rada brzmi „uruchom to na maszynie z Windows”. Nie musisz. Z Wine możesz uruchomić serwer Windows na zwykłej maszynie z Linuksem, a on połączy się ze Steam i przyjmie prawdziwych graczy. To dokładnie ten przepis, który zadziałał u nas, na przykładzie Alien Swarm: Reactive Drop (darmowej gry co-op na silniku Source). To samo podejście powinno działać dla innych serwerów dedykowanych Source dostępnych tylko na Windows.
Najpierw sprawdź, czy naprawdę nie ma serwera Linux
Nie zakładaj z góry. Zapytaj Steam wprost, zanim sięgniesz po Wine. Wskaż steamcmd na aplikację i przeczytaj jej listę platform:
steamcmd +login anonymous +app_info_print <appid> +quit \
| grep -iE "oslist|name"Jeśli aplikacja serwera dedykowanego ma tylko "oslist windows", nie ma natywnego builda na Linuksa, na który można się cofnąć. Możesz też spróbować wymusić instalację na Linuksie; gdy naprawdę nie ma depotu Linux, zawodzi natychmiast:
steamcmd +@sSteamCmdForcePlatformType linux \
+login anonymous +app_update <appid> validate +quit
# ERROR! Failed to install app '<appid>' (Missing configuration)Ten błąd i brak pojawiających się plików ELF to potwierdza. Teraz drogą jest Wine. Zainstaluj serwer ORAZ app 1007 (Steamworks Common Redistributables) do tego samego folderu, z typem platformy windows. App 1007 dostarcza DLL-e Steam, których serwer potrzebuje, a dlaczego, zobaczysz w kroku 2:
steamcmd +@sSteamCmdForcePlatformType windows +login anonymous \
+force_install_dir /path/to/server \
+app_update <appid> validate \
+app_update 1007 validate \
+quitSerwer potrzebuje też środowiska Microsoft Visual C++ 2019 wewnątrz prefiksu Wine. Zainstaluj je raz przez winetricks (wymaga ekranu, więc opakuj to w xvfb-run):
WINEPREFIX=/wine xvfb-run -a winetricks -q vcrun2019
wineserver -wDlaczego naiwna próba z Wine zawodzi
Uruchomienie serwera wprost z Wine napotyka dwie ściany z rzędu:
- Brak konsoli: serwer oczekuje prawdziwego terminala. Przekierowanie z /dev/null daje CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents i nigdy się nie uruchamia.
- Nie można załadować biblioteki Steam: nawet po uruchomieniu wypisuje "Unable to load Steam support library" i nigdy nie rejestruje się w Steam, więc nikt nie może go znaleźć ani na niego wejść.
Obie da się naprawić. Oto pełny przepis.
Krok 1: daj mu prawdziwy terminal (PTY)
Maszyna headless nie ma terminala, a serwer konsolowy Windows bez niego nie działa. Potrzebuje pseudoterminala (PTY), którego strona wejściowa zostaje otwarta, a to właśnie daje docker run -it. Popularna rada to opakować start w script. Na maszynie bez terminala to jest właśnie błąd: wejście samego script trafia na koniec pliku, odczyt konsoli serwera też to widzi i jego pętla główna staje. Mapa może się załadować, ale serwer nigdy nie odpowiada na swoich gniazdach. Zamiast tego uruchom go z małego wrappera w Pythonie, który otwiera PTY i nigdy go nie zamyka, i użyj Xvfb jako sztucznego ekranu:
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.pySamo to sprawia, że serwer ładuje mapę i przypisuje swój port gry. Ale wciąż nie potrafi porozmawiać ze Steam.
Krok 2: dwa DLL-e Steam, dwa różne źródła
Silnik Source potrzebuje OBU, steamclient.dll i steam.dll, obok pliku exe serwera, i tu tkwi pułapka, która kosztowała nas całą dodatkową rundę debugowania: pochodzą z RÓŻNYCH miejsc, a app 1007 daje Ci tylko JEDEN z nich.
- steamclient.dll: pochodzi z app 1007 (Steamworks Common Redistributables), którą zainstalowałeś w kroku 1. Kanoniczny, w zgodnej wersji, utrzymywany przez Valve.
- steam.dll: NIE ma go w app 1007. Jest częścią KLIENTA Steam, a jedynym czystym sposobem, by go zdobyć, jest jednorazowe uruchomienie windowsowego steamcmd.exe pod Wine, który sam się aktualizuje i kładzie steam.dll (oraz steamclient.dll) we własnym folderze.
Uruchom więc steam.dll przez steamcmd.exe pod Wine, a potem skopiuj oba DLL-e obok exe serwera:
# 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" .Krok 3: dlaczego steam.dll to element, który ma znaczenie
To część, której prawie nikt nie zapisuje. Błąd mówi "Unable to load Steam support library," a biblioteką wsparcia, o którą chodzi, nie jest steamclient.dll, tylko steam.dll. Silnik Source szuka steam.dll obok własnego pliku wykonywalnego, aby uruchomić cały łańcuch Steam. Gdy obecny jest tylko steamclient.dll (a tylko tyle daje Ci app 1007), wciąż zawodzi; w chwili, gdy steam.dll leży obok pliku .exe, log przewraca się z porażki na sukces:
Connection to Steam servers successful.
VAC secure mode is activated.VAC nie aktywuje się, dopóki serwer nie jest poprawnie zalogowanym gameserverem, więc ta linijka to Twój dowód, że się zarejestrował. Większość serwerów Source loguje się tu anonimowo i nie potrzebuje żadnego Game Server Login Token (GSLT). Tylko kilka gier (jak CS2) go wymaga.
Pułapka: A2S milknie
Oto pułapka, która kosztowała nas najwięcej czasu. Z wrapperem script serwer NIE odpowiadał na A2S_INFO, zapytanie UDP, którym narzędzia odczytują nazwę serwera, mapę i liczbę graczy. Każde zapytanie kończyło się timeoutem, nawet z tej samej maszyny, więc serwer wyglądał na całkiem martwy. Najpierw obwinialiśmy Wine. To była zatrzymana pętla główna z Kroku 1: serwer w ogóle nie czytał swoich gniazd.
Z otwartym PTY serwer normalnie odpowiada na A2S, a prawdziwi gracze mogą dołączyć. Ostatecznym testem jest wciąż połączenie klienta, nie odpowiedź na zapytanie. Gdy PTY było w porządku, prawdziwy gracz się połączył i grał:
Client "player" connected (10.0.0.5:27005).
1/ 8 on map <mapname>Praktyczna lekcja: jeśli serwer na Wine ładuje mapę, ale A2S milczy, nie obwiniaj najpierw Wine. Sprawdź, jak podpięta jest konsola. Zajęty port UDP nie dowodzi, że serwer żyje, bo zatrzymany serwer trzyma port, a pakiety piętrzą się nieprzeczytane.
Czy to działa dla każdej gry na Windows?
Bądźmy uczciwi co do zakresu. Udowodniliśmy to na serwerze na silniku Source, a ten sam przepis (PTY, środowisko zbudowane przez steamcmd, steam.dll obok exe) powinien działać dla innych serwerów dedykowanych Source tylko dla Windows. Gry na innych silnikach integrują Steam inaczej, więc traktuj je jako osobne eksperymenty. Jedno jest pewne w obu przypadkach: start jest wolniejszy niż natywnie na Linuksie (Wine plus krok steamcmd plus logowanie do Steam).
Albo pomiń to wszystko
To jest ten rodzaj dłubaniny, który zjada całe popołudnie. Jeśli chcesz po prostu serwer, prowadzimy flotę Linuksów i całą instalację Wine za Ciebie, na godziny, z publicznym IP od pierwszej minuty. Alien Swarm: Reactive Drop nie jest jeszcze na naszych publicznych stronach wdrożenia, ale inne serwery tylko dla Windows są, na przykład Wreckfest i rFactor 2. Zobacz wszystko, co hostujemy na 2hours.gg.