Anonim

AIMBOT 2.0

Az Új játék 2. epizódjában, 9:40 körül, van egy lövés a kódról, amelyet Nene írt:

Itt van szöveges formában a lefordított megjegyzésekkel:

// 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(); } } } 

A lövés után Umiko a for hurokra mutatva azt mondta, hogy a kód összeomlott az oka, hogy van egy végtelen hurok.

Nem igazán ismerem a C ++ - t, ezért nem vagyok biztos abban, hogy igaz-e az, amit mond.

Amit látok, a for ciklus csak a színész által jelenleg rendelkezésre álló debuf-eken keresztül ismétlődik. Hacsak a színésznek nincs végtelen mennyiségű debufja, nem hiszem, hogy ez végtelen ciklussá válhat.

De nem vagyok biztos benne, mert az egyetlen oka annak, hogy van egy lövés a kódról, az az, hogy ide akartak tenni egy húsvéti tojást, igaz? Éppen kaptunk volna egy képet a laptop hátuljáról, és meghallottuk Umikót, aki azt mondta: "Ó, itt végtelen hurok van". Az a tény, hogy valóban mutattak valamilyen kódot, arra gondol, hogy valahogy a kód valamiféle húsvéti tojás.

Vajon a kód valóban létrehoz egy végtelen ciklust?

8
  • Valószínűleg hasznos: további képernyőkép arról, hogy Umiko azt mondja, hogy "volt hívja ugyanazt a műveletet újra és újra ", ami esetleg nem jelenik meg a kódban.
  • Oh! Ezt nem tudtam! @AkiTanaka az a rész, amelyet néztem, azt mondja: "végtelen hurok"
  • @LoganM nem igazán értek egyet. Nem csak az OP-nak van kérdése valamilyen forráskódról, amely történetesen egy animéből származik; Az OP kérdése egy adott nyilatkozatra vonatkozik ról ről a forráskódot egy karakterben az anime-ban, és van egy animével kapcsolatos válasz, nevezetesen: "A Crunchyroll megtörtént és félrefordította a sort".
  • @senshin szerintem azt olvasod, amiről szeretnéd a kérdést szólni, nem pedig arról, amit valójában feltesznek. A kérdés tartalmaz néhány forráskódot, és megkérdezi, hogy generál-e egy végtelen ciklust valós C ++ kódként. Új játék! kitalált mű; nincs szükség a benne bemutatott kódra, hogy megfeleljen a való élet szabványainak. Amit Umiko mond a kódról, az hitelesebb, mint bármely C ++ szabvány vagy fordító. A legfelsõbb (elfogadott) válasz nem említ semmilyen univerzumon belüli információt. Azt hiszem, egy témára vonatkozó kérdést fel lehetne tenni erre egy jó válasz mellett, de ahogy megfogalmazták, ez nem igaz.

A kód nem végtelen hurok, hanem hiba.

Két (esetleg három) kérdés van:

  • Ha nincsenek debufok, akkor egyáltalán nem keletkezik kár
  • Túlzott károk keletkeznek, ha több mint 1 debuf van
  • Ha a DestroyMe () azonnal törli az objektumot, és még mindig vannak feldolgozandó m_debuf fájlok, akkor a hurok egy törölt objektumon fog végrehajtani és a memóriába helyez. A legtöbb játékmotornak megsemmisítési sora van ennek és másoknak a kiküszöbölésére, így ez nem lehet kérdés.

A károsodásnak a hurkon kívül kell lennie.

Itt van a javított függvény:

// 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 Kódellenőrzésen vagyunk? : D
  • A 4 úszó kiválóan alkalmas az egészségre, ha nem haladja meg az 16777216 LE értéket. Akár azt is, hogy a végtelenségig állítsa az egészséget, hogy létrehozzon egy olyan ellenséget, amelyet eltalálhat, de nem hal meg, és egy öléses támadást végezhet végtelen sebzéssel, amely még mindig nem öl meg egy végtelen HP karaktert (az INF-INF eredménye NaN), de meg fog ölni minden mást. Tehát nagyon hasznos.
  • 1 @cat Megállapodás szerint sok kódolási szabványban az m_ az előtag azt jelenti, hogy tagváltozó. Ebben az esetben a DestructibleActor.
  • 2 @HotelCalifornia Egyetértek azzal, hogy van egy kis esély ApplyToDamage nem a várt módon működik, de az Ön által megadott példában azt mondanám ApplyToDamage is át kell dolgozni, hogy megkövetelje az eredeti átadását sourceDamage valamint annak érdekében, hogy azokban az esetekben megfelelően ki tudja számolni a debuf-ot. Abszolút pedánsnak lenni: ezen a ponton a dmg információnak olyan struktúrának kell lennie, amely magában foglalja az eredeti dmg-t, az aktuális dmg-t és a kár (ok) jellegét, valamint ha a debuf-eknek vannak olyan dolgai, mint "tűzveszély". Tapasztalat szerint nem sokkal azelőtt, hogy bármelyik debuffel ellátott játék megtervezné ezeket.
  • 1 @StephaneHockenhull jól mondta!

Úgy tűnik, hogy a kód nem hoz létre végtelen ciklust.

A hurok csak akkor lenne végtelen, ha

debuf.ApplyToDamage(resolvedDamage); 

vagy

DestroyMe(); 

új elemeket kellett volna felvenni a m_debufs tartály.

Ez valószínűtlennek tűnik. És ha így lenne, akkor a program összeomolhat, mert a konténert megváltoztatják, miközben iterálnak.

A program valószínűleg összeomlik a hívás miatt DestroyMe(); amely feltehetően elpusztítja a ciklust futtató aktuális objektumot.

Úgy gondolhatunk rá, mint egy rajzfilmre, ahol a „rossz fiú” egy ágat fűrészel, hogy a „jó srác” leessen vele, de túl későn veszi észre, hogy a vágás rossz oldalán áll. Vagy a Midgaard kígyó a saját farkát eszi.


Azt is hozzá kell tennem, hogy a végtelen hurok leggyakoribb tünete az, hogy lefagyasztja a programot, vagy nem reagál. Összeomlik a program, ha ismételten kiosztja a memóriát, vagy olyasmit tesz, ami végül nullával vagy hasonlóakkal oszlik el.


Aki Tanaka megjegyzése alapján

Valószínűleg hasznos: további képernyőkép arról, hogy Umiko azt mondja, hogy "ugyanazt a műveletet hívta újra és újra", ami valószínűleg nem jelenik meg a kódban.

"Ugyanezt a műveletet hívta újra és újra" Ez valószínűbb.

Feltéve, hogy DestroyMe(); nem úgy tervezték, hogy többször is hívható legyen, valószínűbb, hogy összeomlik.

A probléma megoldásának egyik módja a if valami ilyesmire:

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

Ez kilépne a hurokból, amikor a DestructibleActor megsemmisül, és győződjön meg arról, hogy 1) a DestroyMe metódust csak egyszer hívják meg, és 2) ne alkalmazza haszontalanul a buffokat, ha az objektum már halottnak tekinthető.

2
  • 1 Kitörni a for ciklusból, amikor az egészség <= 0 mindenképpen jobb megoldás, mint várni a ciklus után az állapot ellenőrzésére.
  • Azt hiszem, valószínűleg megtenném break ki a hurokból, és azután hívás DestroyMe(), csak hogy biztonságban legyünk

A kóddal számos probléma merül fel:

  1. Ha nincsenek debufok, akkor nem keletkezik kár.
  2. DestroyMe() a funkció neve veszélyesnek hangzik. A megvalósítás módjától függően lehet, hogy nem kérdés. Ha csak egy függvénybe csomagolt aktuális objektum rombolójának hívása, akkor van egy probléma, mivel az objektum a kód közepén végrehajtva elpusztul. Ha egy olyan függvény hívása, amely sorba állítja az aktuális objektum törlési eseményét, akkor nincs probléma, mivel az objektum megsemmisül, miután befejezte végrehajtását és az eseményhurok beindult.
  3. Az a tényleges kérdés, amelyet úgy tűnik, hogy az animében megemlítenek, a "Ugyanezt a műveletet hívta újra és újra" - DestroyMe() amíg m_currentHealth <= 0.f és még több debuff van megismételve, ami azt eredményezheti DestroyMe() többször is hívják, újra és újra. A huroknak az első után le kell állnia DestroyMe() hívást, mert egy objektum többször törlése memóriasérülést eredményez, ami valószínűleg hosszú távon összeomlást eredményez.

Nem igazán vagyok biztos abban, hogy minden debuf miért veszi el az egészséget, ahelyett, hogy az egészséget csak egyszer veszik el, és az összes debuff hatását a kezdeti sérülésre alkalmazzák, de feltételezem, hogy ez a helyes játéklogika.

A helyes kód az lenne

// 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
  • Hangsúlyoznom kell, hogy mivel korábban írtam memóriafoglalókat, ugyanannak a memóriának a törlése nem feltétlenül jelent problémát. Ez felesleges is lehet. Minden a lefoglaló viselkedésétől függ. Az enyém csak úgy viselkedett, mint egy alacsony szintű összekapcsolt lista, így a törölt adatok "csomópontja" vagy többször szabaddá válik, vagy többször újraindul (ami csak a redundáns mutatóátirányításoknak felelne meg). Jó fogás.
  • A dupla mentesség hiba, és általában meghatározatlan viselkedéshez és összeomlásokhoz vezet. Még akkor is, ha van olyan egyéni elosztója, amely valamilyen módon tiltja ugyanazon memóriacím újrafelhasználását, a kettős mentesség büdös kód, mivel nincs értelme, és statikus kódelemzők kiabálják.
  • Természetesen! Nem erre a célra terveztem. Egyes nyelvekben csak a funkciók hiánya miatt van szükség lefoglalóra. Nem nem nem. Csak állítottam, hogy az összeomlás nem garantált. Bizonyos tervezési besorolások nem mindig ütköznek össze.