Anonim

AIMBOT 2.0

A l'episodi 1 de New Game 2, cap a les 9:40, hi ha una captura del codi que Nene ha escrit:

Aquí el teniu en forma de text amb els comentaris traduïts:

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

Després del tret, Umiko, assenyalant el bucle for, va dir que el motiu pel qual es va estavellar el codi és que hi ha un bucle infinit.

Realment no sé C ++, així que no estic segur de si el que diu és cert.

Pel que puc veure, el bucle for només està iterant a través dels debufs que té actualment l'actor. Tret que l'Actor tingui una quantitat infinita de debufs, no crec que es pugui convertir en un bucle infinit.

Però no estic segur perquè l’única raó per la qual hi ha un tret del codi és que volien posar un ou de Pasqua aquí, oi? Hauríem acabat de fer un tret de la part posterior de l’ordinador portàtil i escoltar l’Umiko que deia “Oh, hi tens un bucle infinit”. El fet que en realitat mostressin algun codi em fa pensar que d’alguna manera el codi és un ou de Pasqua.

El codi crearà realment un bucle infinit?

8
  • Probablement útil: captura de pantalla addicional d'Umiko dient que "Va ser trucant a la mateixa operació una i altra vegada ", que pot ser que no es mostri al codi.
  • Oh! No ho sabia! @AkiTanaka, el sub que he vist diu "bucle infinit"
  • @LoganM No estic d'acord. No és només que OP tingui una pregunta sobre algun codi font que prové d’un anime; La pregunta d’OP tracta sobre una declaració concreta feta Sobre el codi font d'un personatge de l'anime, i hi ha una resposta relacionada amb l'anime, és a dir, "Crunchyroll ha estat trampós i ha traduït malament la línia".
  • @senshin Crec que estàs llegint de què vols que es tracti la pregunta, en lloc de què es fa realment. La pregunta proporciona algun codi font i pregunta si genera un bucle infinit com a codi C ++ de la vida real. Nou joc! és una obra fictícia; no cal que el codi que s’hi presenti s’ajusti als estàndards de la vida real. El que Umiko diu sobre el codi és més autoritari que qualsevol estàndard o compilador C ++. La resposta superior (acceptada) no esmenta cap informació de l'univers. Crec que es podria fer una pregunta sobre aquest tema amb una bona resposta, però, tal com està formulat, no ho és.

El codi no és un bucle infinit però sí un error.

Hi ha dos (possiblement tres) problemes:

  • Si no hi ha debufs, no s'aplicarà cap dany
  • S’aplicarà un dany excessiu si hi ha més d’un debuf
  • Si DestroyMe () suprimeix immediatament l'objecte i encara hi ha m_debufs per processar, el bucle s'executarà sobre un objecte suprimit i deixarà a la paperera la memòria. La majoria dels motors de jocs tenen una cua de destrucció per solucionar-ho i, per tant, pot ser que no sigui un problema.

L'aplicació de danys hauria de ser fora del bucle.

Aquí teniu la funció corregida:

// 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 Estem en revisió de codi? : D
  • 4 flotadors són ideals per a la salut si no sobrepasseu els 16777216 CV. Fins i tot podeu establir la salut a infinit per crear un enemic que pugueu colpejar però que no moriu i fer un atac amb una sola mort utilitzant dany infinit que encara no matarà un personatge HP infinit (el resultat d’INF-INF és NaN) però matarà tota la resta. Per tant, és molt útil.
  • 1 @cat Per convenció en molts estàndards de codificació m_ prefix significa que és una variable membre. En aquest cas, una variable membre de DestructibleActor.
  • 2 @HotelCalifornia Estic d'acord que hi ha poques possibilitats ApplyToDamage no funciona com s'esperava, però en el cas d'exemple que donaria, diria ApplyToDamage també s’ha de tornar a treballar per requerir passar-ne l’original sourceDamage també perquè pugui calcular correctament el debuf en aquests casos. Per ser un pedant absolut: en aquest moment la informació dmg hauria de ser una estructura que inclogui la dmg original, la dmg actual i la naturalesa dels danys, també si els debufs tenen coses com "vulnerabilitat al foc". Per experiència, no passa molt abans que qualsevol disseny de jocs amb debufs ho exigeixin.
  • 1 @StephaneHockenhull ben dit!

Sembla que el codi no crea un bucle infinit.

L'única forma en què el bucle seria infinit seria si

debuf.ApplyToDamage(resolvedDamage); 

o bé

DestroyMe(); 

s'havien d 'afegir nous elements al m_debufs contenidor.

Sembla poc probable. I si fos el cas, el programa podria bloquejar-se a causa de canviar el contenidor mentre s’iterava.

El programa probablement es bloquejaria a causa de la trucada a DestroyMe(); que presumiblement destrueix l'objecte actual que actualment executa el bucle.

Podem pensar-ho en el dibuix animat on el "dolent" veu una branca perquè el "bon" caigui amb ell, però s'adona massa tard que està al costat equivocat del tall. O la serp Midgaard menjant la seva pròpia cua.


També he d’afegir que el símptoma més comú d’un bucle infinit és que congela el programa o que no respon. Es bloquejarà el programa si assigna memòria repetidament, o fa alguna cosa que s'acaba dividint per zero o similar.


Basat en el comentari d’Aki Tanaka,

Probablement útil: captura de pantalla addicional d'Umiko dient que "Anava fent la mateixa operació una vegada i una altra", que potser no es mostra al codi.

"Cridava la mateixa operació una i altra vegada" Això és més probable.

Assumint que DestroyMe(); no està dissenyat per cridar-se més d'una vegada, és més probable que provoqui un bloqueig.

Una manera de solucionar aquest problema seria canviar el fitxer if per a alguna cosa així:

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

Això sortiria del bucle quan DestructibleActor es destrueixi, assegurant-vos que 1) DestroyMe mètode es diu només una vegada i 2) no apliqueu inútils buffs una vegada que l'objecte ja es considera mort.

2
  • 1 Sortir del bucle for quan la salut <= 0 és definitivament una millor solució que esperar fins després del bucle per comprovar la salut.
  • Crec que probablement ho faria break fora del bucle i llavors anomenada DestroyMe(), només per estar segur

Hi ha diversos problemes amb el codi:

  1. Si no hi ha debufs, no es patiria cap dany.
  2. DestroyMe() el nom de la funció sona perillós. Depenent de com s’implementi, pot ser que sigui un problema. Si només es tracta d’una trucada al destructor de l’objecte actual embolicat en una funció, hi ha un problema, ja que l’objecte es destruiria al centre d’ell executant codi. Si es tracta d'una trucada a una funció que posa en cua l'esdeveniment de supressió de l'objecte actual, no hi haurà cap problema, ja que l'objecte es destruiria després que finalitzi l'execució i s'iniciï el bucle d'esdeveniments.
  3. El problema real que sembla esmentar-se a l'anime, el "Estava cridant la mateixa operació una i altra vegada": es dirà DestroyMe() sempre que m_currentHealth <= 0.f i queden més debuffs per repetir, cosa que podria resultar DestroyMe() que es crida diverses vegades, una vegada i una altra. El bucle s’ha d’aturar després del primer DestroyMe() trucada, perquè suprimir un objecte més d'una vegada es tradueix en un deteriorament de la memòria, que probablement provocarà un bloqueig a la llarga.

No estic segur de per què cada debuf treu la salut, en lloc de retirar-la una sola vegada, amb els efectes de tots els debuffs sobre els danys inicials presos, però suposo que és la lògica correcta del joc.

El codi correcte seria

// 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
  • He d’assenyalar que, ja que he escrit assignadors de memòria en el passat, l’eliminació de la mateixa memòria no ha de ser un problema. També podria ser redundant. Tot depèn del comportament de l’assignador. El meu simplement va actuar com una llista enllaçada de baix nivell, de manera que el "node" de les dades suprimides es defineix com a lliure diverses vegades o es torna a suprimir diverses vegades (cosa que només correspondria a redireccions de punter redundants). Bona presa, però.
  • El doble de lliure és un error i, en general, comporta bloquejos i comportaments indefinits. Fins i tot si teniu un assignador personalitzat que d’alguna manera prohibeix la reutilització de la mateixa adreça de memòria, el doble de lliure és un codi pudent, ja que no té cap sentit i us analitzaran els analitzadors de codis estàtics.
  • És clar! No el vaig dissenyar amb aquest propòsit. Alguns idiomes només requereixen un assignador per manca de funcions. No no No. Simplement afirmava que no es garanteix un bloqueig. Algunes classificacions de disseny no sempre es bloquegen.