AIMBOT 2.0
V 1. epizodi Nove igre 2, okoli 9:40, je posnetek kode, ki jo je napisala Nene:
Tukaj je v besedilni obliki s prevedenimi komentarji:
// 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 strelu je Umiko, ki je kazal na zanko for, dejal, da je razlog, zakaj se je koda zrušila, ta, da obstaja neskončna zanka.
C ++ v resnici ne poznam, zato nisem prepričan, ali to, kar govori, drži.
Kolikor vidim, zanka for samo prenavlja debufe, ki jih igralec trenutno ima. Če igralec nima neskončne količine napak, mislim, da ne more postati neskončna zanka.
Nisem pa prepričan, ker je edini razlog, da je prišlo do kode, ta, da so tu radi dali velikonočno jajce, kajne? Pravkar bi dobili posnetek zadnje strani prenosnega računalnika in slišali Umiko, ki je rekel: "Oh, tam imaš neskončno zanko". Dejstvo, da so dejansko pokazali neko kodo, mi daje misliti, da je nekako nekakšno velikonočno jajčece.
Bo koda dejansko ustvarila neskončno zanko?
8- Verjetno koristno: dodatni posnetek zaslona Umiko, ki pravi, da "Bilo je klicanje iste operacije znova in znova ", ki v kodi morda ne bo prikazana.
- Oh! Tega nisem vedel! @AkiTanaka, sub, ki sem si ga ogledal, pravi "neskončna zanka"
- @LoganM V resnici se ne strinjam. Ne gre samo za to, da ima OP vprašanje o neki izvorni kodi, ki je prišla iz animeja; Vprašanje OP se nanaša na določeno izjavo približno izvorno kodo z znakom v animeju, in na anime je povezan odgovor, in sicer "Crunchyroll je naredil goofed in napačno prevedel vrstico".
- @senshin Mislim, da berete tisto, za kar želite, da gre za vprašanje, in ne o tem, kaj je dejansko postavljeno. Vprašanje vsebuje nekaj izvorne kode in sprašuje, ali ustvarja neskončno zanko kot resnično kodo C ++. Nova igra! je izmišljeno delo; ni potrebe, da je koda, ki je v njej predstavljena, v skladu z resničnimi standardi. Kar Umiko pravi o kodi, je bolj verodostojno kot kateri koli standard ali prevajalniki C ++. V zgornjem (sprejetem) odgovoru ni nobene informacije o vesolju. Mislim, da bi o tem lahko postavili vprašanje na temo z dobrim odgovorom, toda kot je postavljeno, to ni to.
Koda ni neskončna zanka, je pa napaka.
Obstajata dve (morda tri) težave:
- Če ne obstajajo razhroščevalne datoteke, škoda sploh ne bo uporabljena
- Če je več kot 1 razhroščevanje, bo nastala prekomerna škoda
- Če DestroyMe () objekt takoj izbriše in še vedno obstajajo m_debufs, ki jih je treba obdelati, se zanka izvede nad izbrisanim predmetom in premakne pomnilnik. Večina igralnih mehanizmov ima čakalno vrsto za uničenje, da bi se izognili temu in še več, zato morda ni problem.
Poškodba mora biti zunaj zanke.
Tukaj je popravljena funkcija:
// 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 Smo na pregledu kode? : D
- 4 plovci so odlični za zdravje, če ne greste nad 16777216 HP. Lahko celo nastavite zdravje za neskončno, da ustvarite sovražnika, ki ga lahko udarite, vendar ne bo umrl, in imate napad z enim ubijanjem z uporabo neskončne škode, ki še vedno ne bo ubila neskončnega znaka HP (rezultat INF-INF je NaN), vendar bo ubil vse ostalo. Torej je zelo koristno.
- 1 @cat Po dogovoru v mnogih standardih kodiranja je
m_
predpona pomeni, da gre za spremenljivko člana. V tem primeru je spremenljivka članaDestructibleActor
. - 2 @HotelCalifornia Strinjam se, da je majhna možnost
ApplyToDamage
ne deluje po pričakovanjih, ampak v primeru, ki ga navedete, bi rekelApplyToDamage
tudi je treba predelati, da bo treba posredovati izvirniksourceDamage
pa tudi, da lahko v teh primerih pravilno izračuna debuf. Da bi bili absolutni pedant: na tej točki bi morali biti podatki o dmg strukturirani, ki vključujejo prvotni dmg, trenutni dmg in naravo škode, če imajo razhroščevalni elementi na primer "ranljivost na ogenj". Iz izkušenj je kmalu pred tem, da jih zahteva kakšna zasnova iger z napakami. - 1 @StephaneHockenhull dobro rečeno!
Zdi se, da koda ne ustvarja neskončne zanke.
Edini način, da bi bila zanka neskončna, bi bil, če
debuf.ApplyToDamage(resolvedDamage);
ali
DestroyMe();
so dodali nove predmete v m_debufs
posoda.
To se zdi malo verjetno. In če bi bilo tako, bi se program lahko zrušil zaradi spremembe vsebnika med ponavljanjem.
Program bi se najverjetneje zrušil zaradi klica DestroyMe();
ki verjetno uniči trenutni objekt, ki trenutno izvaja zanko.
Lahko si ga predstavljamo kot risanko, kjer 'slabi moški' žaga vejo, da bi z njo padel tudi 'dobri fant', vendar prepozno ugotovi, da je na napačni strani reza. Ali pa Midgaard Snake, ki je svoj rep.
Prav tako moram dodati, da je najpogostejši simptom neskončne zanke ta, da program zamrzne ali pa se ne odziva. Program bo zrušil program, če večkrat dodeli pomnilnik ali naredi nekaj, kar se na koncu deli z ničlo ali všečke.
Na podlagi komentarja Akija Tanake je
Verjetno koristno: dodatni posnetek zaslona Umiko, ki pravi, da "Vedno znova je klical isto operacijo", ki v kodi morda ni prikazana.
"Vedno znova je klical isto operacijo" To je bolj verjetno.
Predvidevam da DestroyMe();
ni zasnovan tako, da bi bil poklican večkrat, je verjetneje, da bo povzročil zrušitev.
Način, kako odpraviti to težavo, bi bil spremeniti if
za nekaj takega:
if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; }
To bi zapustilo zanko, ko je DestructibleActor uničen, pri tem pa zagotovite, da 1) DestroyMe
metoda se pokliče samo enkrat in 2) ne uporabljajte navdušencev neuporabno, ko je predmet že ocenjen kot mrtev.
- 1 Prekinitev zanke for, ko je zdravje <= 0, je vsekakor boljši popravek kot čakanje na zanko za preverjanje zdravja.
- Mislim, da bi verjetno
break
izven zanke in potem pokličiteDestroyMe()
, samo da sem na varnem
S kodo je več težav:
- Če ni napak, ne bo nastala škoda.
DestroyMe()
ime funkcije zveni nevarno. Glede na to, kako se izvaja, lahko gre za težavo ali ne. Če gre le za klic destruktorja trenutnega predmeta, ovitega v funkcijo, potem obstaja težava, saj bi bil objekt uničen sredi izvajanja kode. Če gre za klic funkcije, ki v čakalni vrsti izbriše dogodek trenutnega predmeta, potem ni nobene težave, saj bi bil objekt uničen po zaključku izvajanja in vklopu zanke dogodka.- Dejanska težava, ki se zdi, da je omenjena v animeju, "Vedno znova je klicala isto operacijo" - poklicala bo
DestroyMe()
doklerm_currentHealth <= 0.f
in še več razveljavitev je za ponovitev, kar bi lahko povzročiloDestroyMe()
večkrat, znova in znova. Zanka se mora ustaviti po prviDestroyMe()
klic, ker brisanje predmeta večkrat povzroči pokvar pomnilnika, kar bo dolgoročno verjetno povzročilo zrušitev.
Nisem prav prepričan, zakaj vsak debuf odvzame zdravje, namesto da bi ga odvzeli le enkrat, pri čemer so bili učinki vseh debuffov uporabljeni na prvotno prevzeto škodo, vendar predvidevam, da je to pravilna logika igre.
Pravilna koda bi bila
// 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 - Poudariti moram, da, kot sem že pisal razdeljevalce pomnilnika, brisanje istega pomnilnika ni nujno težava. Lahko bi bil tudi odveč. Vse je odvisno od vedenja razdeljevalca. Moj se je obnašal kot nizkopovezani seznam, zato se "vozlišče" za izbrisane podatke večkrat sprosti ali večkrat odstrani (kar bi ustrezalo odvečnim preusmeritvam kazalcev). Dober ulov pa.
- Double-free je napaka in na splošno vodi do nedefiniranega vedenja in zrušitev. Tudi če imate razdelilnik po meri, ki nekako onemogoča ponovno uporabo istega pomnilniškega naslova, je dvojno brezplačno smrdljiva koda, saj nima smisla in vas bodo vzklikali statični analizatorji kod.
- Seveda! Nisem ga oblikoval v ta namen. Nekateri jeziki zaradi pomanjkanja funkcij zahtevajo samo razdeljevalnik. Ne ne ne. Samo izjavil sem, da nesreča ni zagotovljena. Nekatere klasifikacije oblikovanja se ne zrušijo vedno.