Anonim

AIMBOT 2.0

V epizóde 1 Novej hry 2, okolo 9:40, je výstrel z kódu, ktorý Nene napísala:

Tu je textová forma s preloženými komentármi:

// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); } } } 

Po výstrele Umiko a ukázal na slučku for povedal, že príčinou zrútenia kódu je to, že existuje nekonečná slučka.

C ++ vlastne neviem, takže si nie som istý, či to, čo hovorí, je pravda.

Z toho, čo vidím, je cyklus for iba iterácia ladením, ktoré herec v súčasnosti má. Pokiaľ nemá herec nekonečné množstvo ladiacich nástrojov, nemyslím si, že by sa z neho mohla stať nekonečná slučka.

Ale nie som si istý, pretože jediný dôvod, prečo je tu kód, je ten, že sem chceli dať veľkonočné vajíčko, však? Akurát by sme dostali výstrel do zadnej časti notebooku a počuli by sme, ako Umiko hovorí: „Máte tam nekonečnú slučku“. Skutočnosť, že skutočne ukázali nejaký kód, ma núti myslieť si, že ten kód je nejakým spôsobom veľkonočné vajíčko.

Vytvorí kód skutočne nekonečnú slučku?

8
  • Pravdepodobne užitočné: ďalšia snímka obrazovky, na ktorej Umiko hovorí: „Bolo volanie tej istej operácie znova a znova “, ktoré sa v kóde nemusia zobraziť.
  • Och! To som nevedel! @AkiTanaka, sub, ktoré som sledoval, hovorí „nekonečná slučka“
  • @LoganM veľmi nesúhlasím. Nejde len o to, že OP má otázku o nejakom zdrojovom kóde, ktorý náhodou pochádzal z anime; Otázka OP sa týka konkrétneho urobeného vyhlásenia o zdrojový kód postavy v anime a existuje odpoveď súvisiaca s anime, konkrétne „Crunchyroll urobil falošnú správu a nesprávne preložil riadok“.
  • @senshin Myslím, že skôr ako to, čo sa vlastne pýta, čítate, o čom má byť otázka. Táto otázka poskytuje určitý zdrojový kód a pýta sa, či generuje nekonečnú slučku ako skutočný C ++ kód. Nová hra! je fiktívne dielo; nie je potrebné, aby v ňom uvedený kód zodpovedal skutočným štandardom. To, čo Umiko hovorí o kóde, je smerodajnejšie ako akékoľvek štandardy alebo kompilátory C ++. Najvyššia (prijatá) odpoveď nezmieňuje nijaké informácie vo vesmíre. Myslím si, že na túto otázku je možné položiť otázku na tému s dobrou odpoveďou, ale vo formulovanom znení to tak nie je.

Kód nie je nekonečnou slučkou, ale je to chyba.

Existujú dva (možno tri) problémy:

  • Ak nie sú k dispozícii žiadne ladiace programy, nebude vykonané žiadne poškodenie
  • Ak dôjde k viac ako 1 debufom, dôjde k nadmernému poškodeniu
  • Ak DestroyMe () okamžite vymaže objekt a stále existuje m_debufs, ktoré sa majú spracovať, slučka sa vykoná nad odstráneným objektom a trasuje pamäť. Väčšina herných nástrojov má frontu na zničenie, aby toto a ešte viac obišli, takže to nemusí byť problém.

Aplikácia poškodenia by mala byť mimo slučky.

Tu je opravená funkcia:

// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); } m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); } } 
12
  • 15 Sme na kontrole kódu? : D
  • 4 plaváky sú skvelé pre zdravie, ak neprekročíte 16777216 HP. Môžete dokonca nastaviť zdravie na nekonečné, aby ste vytvorili nepriateľa, ktorého môžete zasiahnuť, ale nezomriete, a vykonať útok jedného zabitia s použitím nekonečného poškodenia, ktoré stále nezabije nekonečný znak HP (výsledok INF-INF je NaN), ale zabije všetko ostatné. Je to teda veľmi užitočné.
  • 1 @cat Podľa konvencie v mnohých štandardoch kódovania m_ prefix znamená, že ide o členskú premennú. V tomto prípade členská premenná DestructibleActor.
  • 2 @HotelCalifornia Súhlasím, že je malá šanca ApplyToDamage nefunguje podľa očakávania, ale v príklade, ktorý uvediete, by som povedal ApplyToDamage tiež je potrebné prepracovať tak, aby vyžadovalo odovzdanie originálu sourceDamage rovnako tak, aby v týchto prípadoch mohol správne vypočítať ladenie. Ak chcete byť absolútnym pedantom: v tomto okamihu by mali byť informáciami o dmg štruktúra, ktorá obsahuje pôvodný dmg, aktuálny dmg a povahu poškodenia (poškodení), ak majú ladiace programy napríklad „zraniteľnosť voči ohňu“. Zo skúseností to nie je dlho predtým, ako si ich bude vyžadovať akýkoľvek herný dizajn s ladením.
  • 1 @StephaneHockenhull dobre povedané!

Zdá sa, že kód nevytvára nekonečnú slučku.

Jediný spôsob, ako by bola slučka nekonečná, by bol keby

debuf.ApplyToDamage(resolvedDamage); 

alebo

DestroyMe(); 

mali pridať nové položky do súboru m_debufs kontajner.

Zdá sa to nepravdepodobné. Ak by to tak bolo, program by mohol zlyhať z dôvodu výmeny kontajnera pri iterácii.

Program by s najväčšou pravdepodobnosťou zlyhal z dôvodu volania na adresu DestroyMe(); ktorý pravdepodobne zničí aktuálny objekt, ktorý práve prevádzkuje slučku.

Môžeme si to predstaviť ako karikatúru, kde „zlý človek“ zazrie konár, aby s ním „dobrý človek“ spadol, ale príliš neskoro si uvedomí, že je na nesprávnej strane rezu. Alebo hada Midgaarda, ktorý žerie svoj vlastný chvost.


Tiež by som mal dodať, že najbežnejším príznakom nekonečnej slučky je to, že program zamrzne alebo nebude reagovať. Ak program opakovane alokuje pamäť alebo urobí niečo, čo sa nakoniec rozdelí na nulu alebo podobne, program to zlyhá.


Na základe komentára Aki Tanaka,

Pravdepodobne užitočné: ďalšia snímka obrazovky, v ktorej Umiko hovorí: „Volávala stále rovnaká operácia“, ktorá sa v kóde nemusí zobraziť.

„Volala stále tá istá operácia“ Je to pravdepodobnejšie.

Za predpokladu, že DestroyMe(); nie je navrhnutý na to, aby sa dal volať viackrát, je pravdepodobnejšie, že spôsobí zlyhanie.

Tento problém by bolo možné vyriešiť zmenou súboru if na niečo také:

 if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; } 

To by ukončilo slučku, keď je DestructibleActor zničený, pričom by ste sa uistili, že 1) DestroyMe metóda sa volá iba raz a 2) zbytočne neaplikujte buffy, akonáhle je objekt už považovaný za mŕtvy.

2
  • 1 Vytrhnutie zo slučky for, keď zdravie <= 0 je určite lepšia oprava, ako čakanie na kontrolu stavu po skončení slučky.
  • Myslím, že asi break zo slučky a potom hovor DestroyMe(), len pre istotu

S kódom je niekoľko problémov:

  1. Ak nie sú k dispozícii žiadne ladiace programy, nedošlo by k žiadnemu poškodeniu.
  2. DestroyMe() názov funkcie znie nebezpečne. Podľa toho, ako je implementovaný, môže alebo nemusí byť problémom. Ak je to iba volanie deštruktoru aktuálneho objektu zabaleného vo funkcii, potom nastáva problém, pretože objekt by bol zničený v jeho strede pri vykonávaní kódu. Ak sa jedná o volanie funkcie, ktorá zaraďuje do frontu udalosť odstránenia aktuálneho objektu, potom nie je problém, pretože objekt by bol zničený po dokončení vykonania a spustení slučky udalostí.
  3. Skutočný problém, ktorý sa zdá byť spomenutý v anime, „Zavolal stále tú istú operáciu“ - zavolá DestroyMe() pokiaľ m_currentHealth <= 0.f a na iteráciu zostáva ďalších debuffov, čo by mohlo viesť k DestroyMe() byť volaný viackrát, znova a znova. Po prvom by sa slučka mala zastaviť DestroyMe() volanie, pretože viacnásobné odstránenie objektu vedie k poškodeniu pamäte, čo bude mať z dlhodobého hľadiska za následok pravdepodobne zlyhanie.

Nie som si úplne istý, prečo každý debuf odoberá zdravie namiesto toho, aby bol odňatý iba raz, pričom sa účinky všetkých debuffov použijú na počiatočné poškodenie, ale budem predpokladať, že je to správna logika hry.

Správny kód by bol

// the calculation of damage when attacked void DestructibleActor::ReceiveDamage(float sourceDamage) { // apply debuffs auto resolvedDamage = sourceDamage; for (const auto& debuf:m_debufs) { resolvedDamage = debuf.ApplyToDamage(resolvedDamage); m_currentHealth -= resolvedDamage if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; } } } 
3
  • Mal by som zdôrazniť, že tak, ako som už v minulosti písal alokátory pamäte, nemusí byť odstránenie rovnakej pamäte problémom. Môže to byť tiež nadbytočné. Všetko závisí od správania prideľovateľa. Baňa fungovala ako zoznam prepojených odkazov na nízku úroveň, takže „uzol“ odstránených údajov bol buď niekoľkokrát nastavený ako voľný, alebo opakovane odstránený (čo by zodpovedalo zbytočným presmerovaniam ukazovateľa). Dobrý úlovok.
  • Double-free je chyba a zvyčajne vedie k nedefinovanému správaniu a zlyhaniu. Aj keď máte vlastný alokátor, ktorý nejakým spôsobom zakazuje opätovné použitie rovnakej adresy pamäte, double-free je páchnuci kód, pretože to nedáva zmysel a budete na neho kričať statickými analyzátormi kódu.
  • Samozrejme! Nenavrhol som to na tento účel. Niektoré jazyky kvôli nedostatku funkcií iba vyžadujú prideliteľa. Nie nie nie. Iba som uviedol, že zrútenie nie je zaručené. Niektoré klasifikácie dizajnu nemusia vždy zlyhať.