Ahoj, volám sa Sergey Kachan a som klientsky vývojár na projekte War Robots. War Robots je tu už mnoho rokov, a počas tejto doby hra nahromadila obrovské množstvo obsahu: roboty, zbrane, drony, titány, piloti, a tak ďalej. Dnes budem hovoriť o tom, ako sú rovnováhy štruktúrované v našom projekte, čo sa s nimi stalo za posledných 11 rokov a ako sme sa s tým zaoberali. Vyváženie v projekte Rovnako ako každý iný projekt, War Robots možno rozdeliť do dvoch častí: meta a core gameplay. je akákoľvek činnosť, ktorá presahuje základný herný cyklus, ale stále ovplyvňuje hru.Toto zahŕňa nákup a aktualizáciu herného obsahu, účasť na spoločenských alebo udalostných aktivitách. Meta gameplay (metagaming) je hlavný opakujúci sa cyklus akcií, ktoré hráč vykonáva v hre na dosiahnutie svojich cieľov.V našom prípade ide o bitky robotov na konkrétnych mapách. Core gameplay (core gameplay loop) Každá časť projektu potrebuje svoju vlastnú rovnováhu, takže rovnováhy rozdeľujeme aj do dvoch kategórií – meta a jadro. Vojnoví roboti majú tiež tzv. , ktoré si vyžadujú vlastné samostatné rovnováhy. Skirmish modes a je modifikácia existujúcich režimov alebo máp s rôznymi charakteristikami alebo pravidlami. Skirmish režimy sú často založené na udalostiach, k dispozícii pre hráčov počas rôznych sviatkov, hlavne pre zábavu. Skirmish mode Takže celkovo máme 4 rovnováhy: 2 pre predvolený režim a 2 pre režim Skirmish. V priebehu 11 rokov, War Robots nahromadil veľa úžasného obsahu: 95 robotov 21 titánov 175 rôznych zbraní 40 dronov 16 Materská obrovské množstvo koží, remodelov, modulov, pilotov, veží, konečných verzií obsahu a máp A ako si dokážete predstaviť, aby sme vykonali všetku túto prácu, musíme ukladať informácie o správaní, štatistike, dostupnosti, cenách a oveľa, oveľa viac. V dôsledku toho sa naše rovnováhy zvýšili na nevhodnú veľkosť: Default mode Skirmish mode Meta balance 9.2 MB 9.2 MB Core balance 13.1 MB 13.1 MB Meta balance 2.9 MB 2.9 MB Core balance 13.1 MB 13.1 MB Po niekoľkých rýchlych výpočtoch sme zistili, že hráč bude musieť stiahnuť To je dosť veľa! 44.6 MB Naozaj sme nechceli nútiť hráčov, aby sťahovali také veľké množstvo údajov zakaždým, keď sa zmení bilancia. Len aby som vám pripomenul: Vojnové roboty dosiahli V roku 2024 bolo naše mesačné aktívne publikum , a Zapísané každý deň. 300 million registered users 4.7 million people 690 thousand players Teraz si predstavte množstvo dát. Veľa, nie? Mysleli sme si to tiež. Takže sme sa rozhodli urobiť všetko, čo môžeme, aby sme znížili veľkosť našich zostáv! Poľovačka na problém Prvým krokom bolo analyzovať rovnováhy a pokúsiť sa zistiť: "Čo zaberá toľko priestoru?" Manuálne prechádzanie všetkým bolo poslednou vecou, ktorú sme chceli urobiť - to by trvalo roky.Takže sme napísali sadu nástrojov, ktoré zhromažďovali a agregovali všetky informácie, ktoré sme potrebovali o zostatoch. Nástroj by vzal súbor rovnováhy ako vstup a pomocou odrazu iteroval všetky štruktúry, zhromažďoval údaje o tom, aké typy informácií sme uložili a koľko miesta každý z nich zaberal. Výsledky boli odradzujúce: Meta rovnováha % in balance Usage count String 28.478 % 164 553 Int32 27.917 % 161 312 Boolean 6.329 % 36 568 Double 5.845 % 33 772 Int64 4.682 % 27 054 Custom structures 26.749 % — String 28 478 % 164 553 Zobraziť Int32 27 917 % 161 312 Boolean 6 29 % 36 568 žiakov Double 5 845 % 33 772 osôb Int64 4 682 % 27 054 Zľavy Custom structures 26 749 % — Základná rovnováha % in balance Usage count String 34.259 % 232 229 Double 23.370 % 158 418 Int32 20.955 % 142 050 Boolean 5.306 % 34 323 Custom structures 16.11 % — String 34 259 % 232 229 Double 23 370 % 158 418 členov Int32 20 955 % 142 050 Zľavy Boolean 5 306 % 34 323 Custom structures 16,11 % z celkového — Po analýze situácie sme zistili, že A o tom sa muselo niečo robiť. strings were taking up far too much space Ten skenoval súbor rovnováhy a vytvoril mapu všetkých reťazcov spolu s počtom duplikátov. Výsledky tiež neboli povzbudzujúce. Niektoré reťazce sa opakovali desaťtisíce krát! Našli sme problém.A teraz otázka bola: ako to vyriešiť? Optimalizácia rovnováhy Z zjavných dôvodov sme sa nedokázali zbaviť reťazcov úplne. reťazce sa používajú na veci ako lokalizácie a rôzne identifikátory. Myšlienka bola taká jednoduchá, ako sa dostala: Vytvorte zoznam jedinečných reťazcov pre každú rovnováhu (v podstate vyhradený úložný priestor). Odoslať tento zoznam spolu s údajmi. public class BalanceMessage { public BalanceMessageData Data; public StringStorage Storage; public string Version; } StringStorage je v podstate obal okolo zoznamu reťazcov. Keď budujeme reťazec, každá štruktúra rovnováhy si pamätá index reťazca, ktorý potrebuje. public class StringStorage { public List<string> Values; public string GetValue(StringIdx id) => Values[id]; } Namiesto toho, aby sme sami preniesli reťazce do rovnovážnych štruktúr, začali sme prechádzať indexom toho, kde je reťazec uložený v reťazcovom úložisku. predtým : public class SomeBalanceMessage { public string Id; public string Name; public int Amount; } Po tom: public class SomeBalanceMessageV2 { public StringIdx Id; public StringIdx Name; public int Amount; } StringIdx je v podstate len obal okolo int. Týmto spôsobom sme úplne eliminovali priame prenosy reťazcov vo vnútri rovnovážnych štruktúr. public readonly struct StringIdx : IEquatable<StringIdx> { private readonly int _id; internal StringIdx(int value) {_id = value; } public static implicit operator int(StringIdx value) => value._id; public bool Equals(StringIdx other) => _id == other._id; } Tento prístup znížil počet reťazcov desaťnásobne. String usage count String usage count Before After Meta balance 164 553 10 082 Core balance 232 229 14 228 Before After Meta balance 164 553 Zobraziť 10 082 Zľavy Core balance 232 229 14 228 členov Nie je to zlé, však? Ale to bol len začiatok - tam sme sa nezastavili. Prepracovanie dátového protokolu Na spracovanie a spracovanie rovnovážnych štruktúr sme používali . MessagePack MessagePack je binárny formát serializácie údajov navrhnutý ako kompaktnejšia a rýchlejšia alternatíva k JSON.Je určený pre efektívnu výmenu dát medzi aplikáciami alebo službami, čo umožňuje výrazné zníženie veľkosti údajov - obzvlášť užitočné, keď je výkon a šírka pásma dôležité. Spočiatku MessagePack prišiel vo formáte podobnom JSON, kde boli použité údaje To je určite pohodlné, ale aj dosť priestorovo náročné, takže sme sa rozhodli obetovať nejakú flexibilitu a prejsť na . string keys binary byte array predtým : public class SomeBalanceMessage { [Key("id")] public string Id; [Key("name")] public string Name; [Key("amount")] public int Amount; } Po tom: public class SomeBalanceMessageV2 { [Key(0)] public StringIdx Id; [Key(1)] public StringIdx Name; [Key(2)] public int Amount; } Taktiež sme odstránili všetky prázdne zbierky – namiesto ich odosielania teraz prenášame nulové hodnoty, čo znížilo celkovú veľkosť údajov a čas potrebný na serializáciu a deserializáciu. Testovanie zmien Zlatým pravidlom dobrého vývoja (a jedným, ktorý vám ušetrí veľa nervov) je vždy implementovať nové funkcie tak, aby ste ich mohli rýchlo vrátiť späť, ak sa niečo pokazí.Z tohto dôvodu sme pridali všetky nové funkcie za „triky.“ Aby sme túto prácu vykonali, museli sme podporovať dve verzie rovnováhy súčasne: starú a optimalizovanú. Počas vývoja sme sa museli uistiť, že všetky dáta boli správne prenesené. Staré a nové rovnováhy – bez ohľadu na formát alebo štruktúru – museli produkovať presne rovnaké hodnoty. A pamätajte, že optimalizované rovnováhy zmenili svoju štruktúru drasticky, ale nemalo by to ovplyvniť nič okrem ich veľkosti. Aby sme to dosiahli, napísali sme veľké množstvo jednotiek testov pre každú rovnováhu. Spočiatku sme porovnávali všetky polia „na hlavu“ – kontrolovali sme každú jednoznačne. To fungovalo, ale to bolo časovo náročné a aj najmenšia zmena rovnováhy by prerušila testy, čo nás núti neustále ich prepisovať. Nakoniec sme toho mali dosť a prišli sme s pohodlnejším testovacím prístupom na porovnanie rovnováhy. Opäť prišla na záchranu reflexia.Vzali sme dve verzie štruktúr rovnováhy, napríklad SomeBalanceMessage a SomeBalanceMessageV2, a iterovali sme ich – porovnávali sme počty polí, mená a hodnoty.Ak sa niečo nezhodovalo, sledovali sme problém. Optimalizácia výsledkov Vďaka týmto optimalizáciám sa nám podarilo znížiť veľkosť súborov prenášaných cez sieť, ako aj čas potrebný na ich deserializáciu na klienta. veľkosť súboru Old balances Optimized balances Profit Meta balance 9.2 MB 1.28 MB - 86 % Core balance 13.1 MB 2.22 MB - 83 % Meta balance 2.9 MB 1.28 MB - 86 % Core balance 13.1 MB 2 22 MB - 83 % Čas deserializácie Old balances Optimized balances Profit Meta balance 967 ms 199 ms - 79 % Core balance 1165 ms 265 ms - 77 % Meta balance 697 ms 199 ms - 79 % Core balance - 1165 ms 265 ms - 77 % Údaje v pamäti Old balances Optimized balances Profit Meta + Core ~ 45.3 MB ~ 33.5 MB - 26 % Meta + Core - 453 MB ~ 33,5 MB - 26 % závery Výsledky optimalizácie nás plne uspokojili.Bilančné súbory boli znížené o viac ako 80%.Obchod klesol a hráči boli spokojní. Ak to chcete zhrnúť: buďte opatrní s údajmi, ktoré prenášate, a neodosielajte nič zbytočné. Reťazce sú najlepšie uložené v unikátnych úložiskách, aby sa zabránilo vytváraniu duplikátov. A ak vaše vlastné údaje (ceny, štatistiky atď.) tiež obsahujú veľa opakovania, skúste ich zabaliť do unikátnych úložísk.