RE:NODE

Konflikty modů ve Valheimu: závislosti, patche a půlení

Text: Tým RE:NODE
13 min čtení


Když modovaný server Valheimu přestane fungovat poté, co jsi něco přidal nebo aktualizoval, je příčinou téměř vždy jedna ze čtyř věcí: chybějící nebo příliš stará závislost, dva mody patchující stejný kus herního kódu nekompatibilním způsobem, dva mody, které se snaží dělat tutéž práci, nebo klient a server s různými verzemi. První a poslední se ohlásí v logu. Prostřední dvě jsou tišší a jediný spolehlivý způsob, jak je najít, je rozdělit sadu modů na půl a testovat, dokud nezbyde jeden mod. Tento návod ukazuje, jak ty čtyři případy od sebe odlišit, co BepInEx zapíše při každém z nich a jak najít viníka mezi čtyřiceti mody za šest restartů místo čtyřiceti.

Čtyři druhy konfliktů#

Problém se vyplatí pojmenovat dřív, než ho začneš hledat, protože každý druh má jiný příznak a jinou nápravu.

DruhTypický příznakKde se projevíNáprava
Chybějící nebo stará závislostMod se prostě nenačteLogOutput.log při startuNainstaluj nebo aktualizuj knihovnu
Kolidující patcheChyby při použití funkce, divné chováníVýjimky v logu během hryOdeber jeden mod nebo najdi patch pro kompatibilitu
Dva mody, jedna práceZdvojené efekty, rozbité UI, desyncČasto nic v loguNech jen jeden ze dvou
Neshoda verzíVyhození při připojeníZpráva o připojení, log serveruSjednoť sady modů klienta a serveru

Čtvrtý případ vlastně není konflikt mezi mody, ale mezi počítači, a má vlastní návod: vyhazování kvůli neshodě verzí modů podrobně rozebírá hlášení Jotunnu a ServerSync. Tento článek se soustředí na první tři, které vznikají na jednom počítači a rozbijí server nebo hru bez ohledu na to, kdo se připojí.

Užitečná první otázka je, jestli je problém na serveru, na klientech, nebo na obou stranách. Pokud konzole serveru ukazuje chyby ještě před tím, než se kdokoli připojí, jde o sadu modů na serveru. Pokud server naběhne čistě a hra jednoho hráče se chová divně, jde o jeho sadu. Pokud všichni hráči vidí stejně rozbitou funkci, jde obvykle o mod nainstalovaný na obou stranách a ladit ho můžeš na tom počítači, který se snáz restartuje - zpravidla na klientovi.

Řetězce závislostí a co o nich říká BepInEx#

Jen velmi málo modů pro Valheim stojí samo. Obsahové mody se opírají o Jotunn, sdílenou modovací knihovnu; mnoho oblíbených modů obsahuje ServerSync pro posílání konfigurace klientům; samotný Jotunn potřebuje HookGenPatcher. Balíček modu na Thunderstore je deklaruje v souboru manifest.json jako řetězce závislostí ve tvaru Autor-Název-Verze:

manifest.json
{  "name": "ExampleMod",  "version_number": "1.4.0",  "dependencies": [    "denikson-BepInExPack_Valheim-5.4.2202",    "ValheimModding-Jotunn-2.20.0"  ]}

Verze v tom řetězci je verze, proti které autor mod sestavil, ne striktní zámek. r2modman a další správci modů ji přečtou a závislost za tebe nainstalují, obvykle v nejnovější verzi. Ruční instalace to nedělá: když zkopíruješ jediný soubor .dll do BepInEx/plugins bez jeho knihovny, BepInEx ho odmítne načíst. Na serveru je to nejčastější cesta k modu, který všem hráčům funguje a na serveru tiše nedělá nic, protože server byl nastaven ručně a klienti přes správce. Thunderstore a r2modman pro skupiny popisuje, jak obě strany držet v souladu.

Uvnitř souboru .dll plugin deklaruje stejné vztahy vůči BepInEx pomocí atributů a chain loader BepInEx je při startu vynucuje:

  • Tvrdá závislost znamená „nenačítej mě bez tohoto“. Pokud chybí, mod se přeskočí.
  • Měkká závislost znamená „pokud je tohle přítomné, načti to před mnou“. Když chybí, nic se nerozbije; mod jen přijde o případnou integraci.
  • Nekompatibilita znamená „nenačítej mě, pokud je přítomné tohle“. Autoři ji přidávají, když vědí, že dva mody nemohou koexistovat.
  • Minimální verze u tvrdé závislosti znamená, že knihovna musí mít alespoň danou verzi, takže starý Jotunn kontrolou neprojde, i když je nainstalovaný.

Každá z těchto situací vytvoří v logu konkrétní řádek. U BepInEx 5, který je v balíčku pro Valheim, vypadají takto (názvy jsou jen příklady):

BepInEx/LogOutput.log
[Info   :   BepInEx] Loading [Jotunn 2.20.0][Error  :   BepInEx] Could not load [ExampleMod 1.4.0] because it has missing dependencies: com.jotunn.jotunn (v2.21.0 or newer)[Error  :   BepInEx] Could not load [OtherMod 2.0.1] because it is incompatible with: some.other.mod[Warning:   BepInEx] Skipping [ExampleMod 1.3.0] because a newer version exists (ExampleMod 1.4.0)

Závislost je pojmenována podle GUID pluginu, ne podle názvu na Thunderstore, proto se objeví com.jotunn.jotunn místo ValheimModding-Jotunn. GUID se obvykle dá odhadnout; když ne, hledej ho na stránce modu na Thunderstore nebo v jeho README. Řádek „Skipping“ znamená, že jsou nainstalované dvě kopie téhož modu, typicky jedna v plugins a druhá v podsložce zbylé po dřívější ruční instalaci. BepInEx načte novější, což je v pořádku, dokud novější nesmažeš a stará kopie neožije. Kdykoli ten řádek uvidíš, duplicity odstraň.

Kolidující patche#

Skoro každý mod pro Valheim funguje tak, že za běhu patchuje metody samotné hry pomocí Harmony (BepInEx obsahuje fork HarmonyX). Patch může spustit kód před metodou hry (prefix), po ní (postfix), nebo přímo přepsat instrukce metody (transpiler). Stejnou metodu může patchovat mnoho modů a obvykle spolu vycházejí, protože každý postfix jen přidá trochu chování navrch. Potíže začínají ve třech situacích:

  1. Prefix, který přeskočí originál. Prefix může Harmony říct, aby metodu hry vůbec nespouštělo. Pokud mod A takto nahradí kontrolu craftingu a postfix modu B počítal s tím, že originál proběhl, mod B teď pracuje s hodnotami, které nikdy nebyly nastaveny.
  2. Dva transpilery na jedné metodě. Transpiler hledá určitou posloupnost instrukcí a přepisuje ji. Pokud tuto posloupnost už přepsal jiný transpiler, ten druhý nenajde, co hledal, a buď se neaplikuje, nebo se aplikuje na špatném místě.
  3. Patch proti kódu, který se změnil. Po aktualizaci hry může být metoda přejmenovaná, odstraněná nebo přepsaná. Patche proti ní selžou a každý mod, který se na ně spoléhal, přijde o danou funkci.

Selhání patchů při startu zaznamená HarmonyX spolu s metodou, kterou se nepodařilo patchnout, a se stack trace. Problémy s patchi během hry se projeví jako výjimky, jejichž stack trace obsahuje jmenný prostor modu - NullReferenceException vyhozená uvnitř SomeAuthor.SomeMod.Patches.InventoryGui_Patch ti řekne, který mod běžel, když se to pokazilo, i když chyba nemusí být v něm. Přečti celý trace: mod nahoře je ten, který spadl, ale rámec o kus níže od jiného modu bývá ten, který změnil stav, o nějž se ten první zakopl.

Žádný vestavěný přehled o tom, které mody patchují kterou metodu, neexistuje. V praxi na tyto kolize přijdeš tak, že si všimneš, že rozbitá funkce patří do oblasti, které se dotýkají dva tvoje mody - inventář, crafting, pokládání staveb, mapa - a otestuješ to s jedním z nich odebraným.

Dva mody, jedna práce#

Nejtišší konflikt jsou dva mody, které každý o sobě fungují dokonale a nikdy by neměly být nainstalované spolu. Nic nevyhodí chybu; jen dostaneš zdvojené nebo si odporující chování. Tyto překryvy se v seznamech modů skupin objevují znovu a znovu:

OblastCo se překrýváCo uvidíš
Velikost inventářeDva mody rozšiřující inventář, nebo jeden plus all-in-oneChybějící řady, předměty mizející ve skrytých slotech
Práce s kontejneryMody pro quick stack, řazení a zahazováníZdvojená tlačítka, předměty přesunuté dvakrát
Sdílené truhlyTruhla pro více uživatelů plus stackovací mod, který ji nepodporujeDesync, odmítnuté přesuny
Crafting z truhelDva mody pro crafting z kontejnerůSuroviny započítané dvakrát nebo vůbec
Velikosti stacků, nosnostAll-in-one plus specializovaný modJedna konfigurace tiše přepíše druhou
MapaNěkolik modů s pinami nebo minimapouDuplicitní piny, překrývající se panely

Někteří autoři tyto kolize dokumentují. Stránka MultiUserChest uvádí, že QuickStore, QuickStack a SimpleSort způsobují desync a vedle něj nenaběhnou, a doporučuje místo nich Quick Stack Store Sort Trash Restock; ten se zase deklaruje jako nekompatibilní s Trash Items, protože zahazování už obsahuje. Před přidáním každého modu si přečti sekci „Incompatible“ nebo „Known issues“ na jeho stránce a porovnej s ní svůj stávající seznam. Mody pro pohodlí hry pro skupiny probírá běžné mody pro kontejnery a mapu a které z nich spolu vycházejí.

All-in-one mody si zaslouží vlastní varování. Forky Valheim Plus a podobné balíčky mění desítky systémů najednou - velikosti stacků, stavění, crafting, sdílení mapy, inventář. Přidat k nim jakýkoli úzce zaměřený mod je sázka, protože all-in-one už tu oblast pravděpodobně patchuje. Pokud ho vaše skupina používá, ber ho jako základ seznamu a každé další přidání porovnej s jeho výčtem funkcí.

Jak správně číst LogOutput.log#

Všechno výše závisí na tom, že jeden soubor čteš dobře. BepInEx zapisuje BepInEx/LogOutput.log při každém startu a přepisuje předchozí, takže ho před restartem zkopíruj, chceš-li porovnávat běhy. Na serveru můžeš tytéž řádky sledovat i v konzoli, i když v souboru se hledá snáz.

Zdravý start probíhá zhruba v tomto pořadí:

  1. Řádky preloaderu a Doorstopu. Pokud se log zastaví tady, je rozbitý samotný BepInEx - viz server padá při startu.
  2. Řádek Loading [Name Version] pro každý plugin, v pořadí podle závislostí.
  3. Chainloader startup complete, po kterém přebírá řízení hra.
  4. Řádky hry: načítání světa, registrace serveru, join kód na serveru s crossplay.

Vše mezi kroky 2 a 3 je vlastní start modů. Mod, který se načte, ale pak vyhodí výjimku ve své metodě Awake, bude v seznamu uveden jako načtený a přesto nebude fungovat, takže se nezastavuj u hledání Could not load - hledej také Exception a [Error. Varování jsou většinou šum; chyby stojí za přečtení pokaždé. Čtení logů BepInEx jde hlouběji do selhání preloaderu a Doorstopu.

Na klientovi leží stejný soubor ve složce profilu r2modman, ne ve složce hry, což lidi překvapuje. Nastavení r2modman má tlačítko pro otevření složky profilu; log je v její podsložce BepInEx.

Půlení rozbité sady modů#

Když log viníka nejmenuje, rozpůl seznam. Působí to pomalu a přitom je to nejrychlejší metoda, jaká existuje: se 40 mody zbyde po šesti kolech jeden podezřelý. Postup:

  1. Pracuj na kopii. Nejdřív zálohuj svět a celou složku BepInEx. Testování s polovinou obsahových modů odebraných může při uložení smazat jejich předměty a stavební prvky ze světa, takže nikdy nepůl proti živému světu. Správné místo je testovací server nebo lokální kopie světa.
  2. Udělej problém opakovatelný. Zapiš si přesnou akci, která selhává: „crafting v kovárně vyhodí chybu“, „server se zastaví u chain loaderu“. Pokud ho nedokážeš vyvolat na požádání, nemůžeš ho půlit.
  3. Nech knihovny. Jotunn, HookGenPatcher a další knihovny zůstávají v každém kole. Testuješ mody, které je používají.
  4. Odeber polovinu. Přesuň polovinu zbývajících modů z BepInEx/plugins do složky mimo něj, například plugins-disabled vedle BepInEx. V r2modman je místo toho vypni.
  5. Otestuj. Pokud problém zmizel, viník je v polovině, kterou jsi odebral: vrať ji zpět a odeber tu druhou. Pokud problém trvá, je v polovině, která zůstala nainstalovaná.
  6. Opakuj na podezřelé polovině, dokud nezbyde jediný mod.
bash
# On a Linux server, park half the mods outside the plugins folder$ mkdir -p ~/server/plugins-disabled$ mv ~/server/BepInEx/plugins/{ModA,ModB,ModC,ModD}* ~/server/plugins-disabled/$ ls ~/server/BepInEx/plugins

Dvě komplikace. Zaprvé, konflikt potřebuje dva mody, takže problém může zmizet v obou polovinách. Když se to stane, je v každé polovině jeden podezřelý: nech jednu polovinu plně nainstalovanou a druhou půl, dokud se problém nevrátí, a tím získáš první mod; pak to samé udělej obráceně, abys našel jeho partnera. Zadruhé, odebraný mod, na kterém ostatní závisejí, stáhne s sebou i ty závislé. Po každém kole zkontroluj v logu nové řádky Could not load, abys věděl, co skutečně běželo.

Na RE:NODE umí správce souborů přesouvat a přejmenovávat soubory v BepInEx/plugins bez klienta SFTP a konzole ukazuje řádky BepInEx průběžně, takže jedno kolo půlení je přesun, restart a rolování logem. Před prvním kolem vytvoř zálohu na záložce Backups a zamkni ji, aby ji rotace během testování neodstranila - jak zamykání funguje, najdeš v části o zálohách.

Konflikty konfigurace a synchronizovaná nastavení#

Některé konflikty žijí v konfiguraci, ne v kódu. Dva mody, které oba nabízejí nastavení velikosti stacku nebo nosnosti, uplatní každý to své a vyhraje ten, který běží poslední. Řešení je nastavit hodnotu jen v jednom z nich a druhý nechat na výchozí hodnotě nebo vypnutý.

Synchronizované konfigurace přidávají další vrstvu. Mody používající ServerSync nebo synchronizaci konfigurace z Jotunnu posílají hodnoty ze serveru každému klientovi při připojení a po dobu připojení přepisují jeho vlastní soubor. Hráč, který upraví svůj lokální config a nevidí žádnou změnu, tedy nenarazil na chybu: hodnota ze serveru vítězí. Platí to i obráceně - úprava souboru na serveru je jediný způsob, jak změnit synchronizované nastavení pro všechny. Nastavení, která nejsou označena jako synchronizovaná, zůstávají u každého hráče zvlášť a dva hráči mohou mít legitimně různé hodnoty. Podrobnosti včetně zamčených konfigurací a nastavení jen pro adminy jsou v článku ServerSync a vynucování konfigurace.

Při půlení jsou konfigurační soubory past. Soubor .cfg odebraného modu zůstává v BepInEx/config, což je neškodné, ale mod, který čte nastavení jiného modu, se může chovat jinak podle toho, které konfigurace existují. Pokud problém přežije všechna kola půlení, zkus složku BepInEx/config úplně odsunout stranou, aby každý mod startoval s výchozími hodnotami. Pokud to pomůže, viníkem je nastavení, ne mod.

Jak konfliktům předcházet na serveru pro skupinu#

Většina konfliktů na skupinových serverech vzniká změnou několika věcí najednou. Pár návyků jich zabrání většině:

  • Jedna změna na restart. Přidej nebo aktualizuj jeden mod, restartuj, otestuj, pak další. Když se něco rozbije, už víš, která změna to způsobila.
  • Před aktualizací si přečti changelog. Autoři tam uvádějí nové závislosti a ztracenou kompatibilitu. Nová tvrdá závislost na knihovně, kterou nemáš, rozbije mod na ručně udržovaném serveru.
  • Měj po ruce funkční kopii. Po každém funkčním stavu zazálohuj BepInEx/plugins a BepInEx/config. Návrat je pak zkopírování složky, ne vzpomínání na čtyřicet čísel verzí.
  • Upřednostni specializované mody před překrývajícími se. Jeden mod na jednu práci. Pokud obě nabízejí stejnou funkci, v jednom z nich ji vypni.
  • V den patche aktualizace zadrž. Patch hry může rozbít patche v mnoha modech najednou, což vypadá jako sto konfliktů, i když je příčina jediná - co dělat, když aktualizace modu něco rozbije se věnuje čekání.

Základy samotné instalace, pokud sestavuješ seznam od nuly, najdeš v návodu k serveru s BepInEx.

FAQ#

Jak poznám, který mod padá můj server Valheim?

Otevři BepInEx/LogOutput.log a hledej Could not load, potom Exception. Stack trace výjimky obvykle obsahuje jmenný prostor modu, který běžel. Pokud log neřekne nic užitečného, půl: odeber polovinu modů, otestuj a půl dál tu polovinu, která obsahuje problém.

Musím závislosti na serveru instalovat ručně?

Ano, pokud jsi mody serveru nenainstaloval správcem, který je řeší sám. Každá tvrdá závislost uvedená na stránce modu na Thunderstore musí být v BepInEx/plugins v požadované nebo novější verzi, jinak BepInEx mod při startu přeskočí.

Mohou spolu fungovat dva mody, které patchují totéž?

Často ano. Většina patchů jen přidává chování po proběhnutí metody hry a více takových patchů spolu vychází. Problémy nastávají, když jeden mod původní metodu úplně nahradí nebo přepíše její instrukce, a proto jsou mody zasahující do téže oblasti - inventář, crafting, stavění - prvním párem k otestování.

Proč mod funguje kamarádům, ale na serveru ne?

Obvykle proto, že server byl nastaven ručně a chybí mu knihovna, kterou kamarádům nainstaloval jejich správce modů, nebo proto, že server má v podsložce starší kopii modu. Zkontroluj v logu serveru řádky Could not load a Skipping.

Poškodí odebrání modu při testování můj svět?

Může. Když obsahový mod chybí, svět nemůže načíst jeho předměty ani stavební prvky a uložení je zahodí. Půl vždy na kopii světa a potom obnov zálohu, místo abys testoval na světě, na kterém hraje vaše skupina.