Mans vārds ir Sergejs Kachan, un es esmu klientu izstrādātājs projektā War Robots. War Robots ir bijis apkārt daudzus gadus, un šajā laikā spēle ir uzkrājusi milzīgu daudzveidību satura: roboti, ieroči, bezpilota lidaparāti, titāni, piloti, un tā tālāk. Šodien es runāšu par to, kā līdzsvars ir strukturēts mūsu projektā, kas ar viņiem ir noticis pēdējo 11 gadu laikā un kā mēs ar to esam risinājuši. Līdzsvars projektā Tāpat kā jebkurš cits projekts, War Robots var iedalīt divās daļās: meta un pamata spēle. ir jebkura darbība, kas pārsniedz spēļu pamata slieksni, bet joprojām ietekmē spēli.Tā ietver spēļu satura iegādi un atjaunināšanu, dalību sociālajās vai pasākumu aktivitātēs. Meta gameplay (metagaming) ir galvenais atkārtojošais darbību cikls, ko spēlētājs spēlē, lai sasniegtu savus mērķus. Core gameplay (core gameplay loop) Katrai projekta daļai ir vajadzīgs savs līdzsvars, tāpēc mēs arī sadalām līdzsvaru divās kategorijās - meta un kodols. Roboti ir arī tā sauktie , kas prasa savu atsevišķo līdzsvaru. Skirmish modes A ir esošo režīmu vai karšu modifikācija ar dažādām iezīmēm vai noteikumiem. Skirmish režīmi bieži ir balstīti uz notikumiem, kas ir pieejami spēlētājiem dažādās brīvdienās, galvenokārt izklaides nolūkā. Skirmish mode Tātad kopumā mums ir 4 bilances: 2 noklusējuma režīmā un 2 Skirmish režīmā. Vairāk nekā 11 gadus War Robots ir uzkrājis daudz pārsteidzoša satura: 95 roboti 21 titāns 175 dažādi ieroči 40 droni 16 māmiņas milzīgs skaits skins, pārveidojumi, moduļi, pilots, torņi, galīgās versijas satura un kartes Un, kā jūs varat iedomāties, lai veiktu visu šo darbu, mums ir nepieciešams uzglabāt informāciju par uzvedību, statistiku, pieejamību, cenām un daudz, daudz ko citu. Tā rezultātā mūsu bilances ir pieaugušas līdz neatbilstošam izmēram: Default mode Skirmish mode Meta balance 9.2 MB 9.2 MB Core balance 13.1 MB 13.1 MB Meta balance 9.2 MB 9.2 MB Core balance 13.1 MB 13.1 MB Pēc dažiem ātrajiem aprēķiniem mēs atklājām, ka spēlētājam būs nepieciešams lejupielādēt Tas ir diezgan daudz! 44.6 MB Mēs patiešām nevēlējāmies piespiest spēlētājus lejupielādēt tik lielu datu daudzumu katru reizi, kad bilance mainās. Tikai, lai atgādinātu jums: kara roboti ir sasnieguši 2024. gadā mūsu ikmēneša aktīvā auditorija bija un Ieslēgts katru dienu. 300 million registered users 4.7 million people 690 thousand players Tagad iedomājieties datu apjomu. Daudz, vai ne? Mēs arī tā domājām.Tāpēc mēs nolēmām darīt visu iespējamo, lai samazinātu mūsu bilances lielumu! Medības uz problēmu Pirmais solis bija analizēt bilances un mēģināt noskaidrot: "Kas aizņem tik daudz vietas?" Manuāli iet cauri visam bija pēdējā lieta, ko mēs gribējām darīt - tas būtu aizņēmies vecumu.Tātad, mēs uzrakstījām rīku kopumu, kas apkopoja un apkopoja visu nepieciešamo informāciju par bilances. Rīks ņemtu bilance failu kā ievadi un, izmantojot atspoguļošanu, iterēt caur visām struktūrām, apkopojot datus par to, kāda veida informāciju mēs uzglabājām un cik daudz vietas katrs aizņēma. Rezultāti bija noraizējoši: Meta līdzsvars % 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 Int32 27 917 % 161 312 Boolean 6 29 % 36 568 skatījumi Double 5 845 % 33 772 Int64 4 682 % 27 054 skatījumi Custom structures 26 749 % — Galvenais līdzsvars % 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 skatījumi Int32 20 955 % 142 050 Boolean 5 306 % 34 323 Custom structures 16,11 % no kopējā — Analizējot situāciju, mēs sapratām, ka Un kaut kas bija jādara par to. strings were taking up far too much space Tātad, mēs izveidojām citu rīku, kas skenēja bilances failu un ģenerēja visu virkņu karti kopā ar to, cik reizes katra no tām tika dublēta. Rezultāti arī nebija iedrošinoši.Dažas ķēdes tika atkārtotas desmitiem tūkstošu reižu! Mēs bijām atraduši problēmu.Tagad jautājums bija: kā mēs to atrisinām? Līdzsvara optimizēšana Acīmredzamu iemeslu dēļ mēs nevarējām vienkārši atbrīvoties no ķēdes. ķēdes tiek izmantotas tādām lietām kā lokalizācijas atslēgas un dažādi ID. Ideja bija tik vienkārša, kā to iegūst: Izveidojiet sarakstu ar unikālām ķēdēm katram līdzsvaram (galvenokārt, īpašu uzglabāšanu). Sūtiet šo sarakstu kopā ar datiem. public class BalanceMessage { public BalanceMessageData Data; public StringStorage Storage; public string Version; } StringStorage būtībā ir iesaiņotājs ap ķēdes sarakstu. Kad mēs veidojam ķēdes uzglabāšanu, katra līdzsvarošanas struktūra atceras vajadzīgās ķēdes indeksu. vēlāk, iegūstot datus, mēs vienkārši nododam indeksu un ātri saņemam vērtību. public class StringStorage { public List<string> Values; public string GetValue(StringIdx id) => Values[id]; } Tā vietā, lai pašas ķēdes nodotu līdzsvarošanas struktūrām, mēs sākām nodot indeksu par to, kur ķēde tiek glabāta ķēdes glabāšanā. Pirms tam: public class SomeBalanceMessage { public string Id; public string Name; public int Amount; } Pēc tam: public class SomeBalanceMessageV2 { public StringIdx Id; public StringIdx Name; public int Amount; } StringIdx būtībā ir tikai iesaiņojums ap int. Tādā veidā mēs pilnībā likvidējām tiešos strāvas pārnesumus līdzsvara struktūrās. 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; } Šī pieeja samazināja strūklaku skaitu desmitiem reižu. 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 10 082 skatījumi Core balance 232 229 14 228 skatījumi Nav slikti, vai ne? Bet tas bija tikai sākums – mēs tur neapstājāmies. Datu protokola pārstrāde Lai pārraidītu un apstrādātu līdzsvara struktūras, mēs izmantojām . MessagePack MessagePack ir bināro datu serializācijas formāts, kas paredzēts kā kompakta un ātrāka alternatīva JSON. tas ir paredzēts efektīvai datu apmaiņai starp lietojumprogrammām vai pakalpojumiem, kas ļauj ievērojami samazināt datu lielumu - īpaši noderīgi, ja runa ir par veiktspēju un joslas platumu. Sākotnēji MessagePack nāca JSON līdzīgā formātā, kur izmantotie dati Tas noteikti ir ērti, bet arī diezgan telpu patērē.Tāpēc mēs nolēmām upurēt kādu elastību un pāriet uz . string keys binary byte array Pirms tam: public class SomeBalanceMessage { [Key("id")] public string Id; [Key("name")] public string Name; [Key("amount")] public int Amount; } Pēc tam: public class SomeBalanceMessageV2 { [Key(0)] public StringIdx Id; [Key(1)] public StringIdx Name; [Key(2)] public int Amount; } Mēs arī noņēma visas tukšās kolekcijas – tā vietā, lai tās nosūtītu, mēs tagad pārsūtām null vērtības. Pārbaudīt izmaiņas Labas attīstības zelta likums (un viens, kas ietaupīs jums daudz nervu) ir vienmēr ieviest jaunas funkcijas tādā veidā, kas ļauj ātri atgriezties, ja kaut kas notiek nepareizi. Attīstības laikā mums bija jāpārliecinās, ka visi dati tika pārsūtīti pareizi. vecajām un jaunajām bilances — neatkarīgi no formāta vai struktūras — bija jāizgatavo tieši tādas pašas vērtības. Lai to panāktu, mēs rakstījām lielu skaitu vienību testu katram balansam. Sākumā mēs salīdzinājām visus laukus “galvā” – pārbaudījām katru atsevišķi. Tas darbojās, bet tas bija laikietilpīgs, un pat mazākās izmaiņas līdzsvaros pārtrauca testus, liekot mums pastāvīgi tos pārrakstīt. Galu galā, mums bija pietiekami daudz no tā un nāca klajā ar ērtāku testēšanas pieeju līdzsvara salīdzināšanai. Atmiņas atkal nāca glābšanai. Mēs paņēmām divas bilance struktūru versijas, piemēram, SomeBalanceMessage un SomeBalanceMessageV2, un iterējām pār tām — salīdzinot lauku skaitļus, vārdus un vērtības. Optimizācijas rezultāti Pateicoties šīm optimizācijām, mums izdevās samazināt gan tīkla pārraidīto failu lielumu, gan laiku, kas nepieciešams, lai tos deserializētu uz klienta. Faila izmērs 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 9.2 MB 1.28 MB 86 % Core balance 13.1 MB 2.22 MB 83 % Deserializācijas laiks Old balances Optimized balances Profit Meta balance 967 ms 199 ms - 79 % Core balance 1165 ms 265 ms - 77 % Meta balance 967 m2 199 mm 79 % Core balance 1165 m2 265 mm 77 % Dati atmiņā Old balances Optimized balances Profit Meta + Core ~ 45.3 MB ~ 33.5 MB - 26 % Meta + Core • 54,3 MB ~ 33,5 MB 26 % Secinājumi Līdzsvara faili tika samazināti par vairāk nekā 80%. satiksme samazinājās, un spēlētāji bija laimīgi. Lai to apkopotu: esiet uzmanīgi ar datiem, kurus pārsūta, un nesūtiet neko nevajadzīgu. Stringi vislabāk tiek glabāti unikālajās atmiņās, lai izvairītos no dublējumiem.Un, ja jūsu pielāgotie dati (cenas, statistika utt.) satur arī daudz atkārtojumu, mēģiniet tos iesaiņot arī unikālajās atmiņās.