AIMBOT 2.0
न्यू गेम 2 के एपिसोड 1 में, 9:40 के आसपास, उस कोड का एक शॉट है जिसे नेने ने लिखा है:
यहाँ यह पाठ रूप में अनुवादित टिप्पणियों के साथ है:
// 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(); } } }
शॉट के बाद, उमिको ने लूप की ओर इशारा करते हुए कहा कि कोड के दुर्घटनाग्रस्त होने का कारण अनंत लूप है।
मैं वास्तव में C ++ नहीं जानता, इसलिए मुझे यकीन नहीं है कि वह जो कह रहा है वह सच है।
मैं जो देख सकता हूं, उसके लिए लूप सिर्फ उन डिफ्यूज़ के माध्यम से पुनरावृत्त कर रहा है जो वर्तमान में अभिनेता के पास है। जब तक अभिनेता के पास अनंत मात्रा में डेब्यू नहीं होता, मुझे नहीं लगता कि यह संभवतः एक अनंत लूप बन सकता है।
लेकिन मुझे यकीन नहीं है क्योंकि एकमात्र कारण यह है कि कोड का एक शॉट है कि वे यहां एक ईस्टर अंडे डालना चाहते थे, है ना? हमने लैपटॉप के पिछले हिस्से में एक शॉट दिया होगा और उमिको को यह कहते हुए सुना होगा कि "ओह, आपको एक अनंत लूप मिला है"। तथ्य यह है कि उन्होंने वास्तव में कुछ कोड दिखाए थे मुझे लगता है कि किसी तरह कोड किसी प्रकार का एक ईस्टर अंडे है।
क्या कोड वास्तव में एक अनंत लूप बनाएगा?
8- संभवतः सहायक: उमिको का अतिरिक्त स्क्रीनशॉट यह कहते हुए कि "यह था उसी ऑपरेशन को कॉल करना बार-बार ", जो कोड में नहीं दिखाया जा सकता है।
- ओह! मुझे नहीं पता था कि! @AkiTanaka जो मैंने देखा वह "अनंत लूप" कहता है
- @LoganM मैं वास्तव में सहमत नहीं हूँ। ऐसा नहीं है कि ओपी के पास कुछ स्रोत कोड के बारे में एक प्रश्न है जो एनीमे से आया है; ओपी का सवाल एक विशेष वक्तव्य के बारे में है के बारे में एनीमे में एक चरित्र द्वारा स्रोत कोड, और एक एनीमे से संबंधित जवाब है, अर्थात् "क्रंचीयरोल ने नासमझ किया और लाइन को गलत किया"।
- @ सेंशिन मुझे लगता है कि आप पढ़ रहे हैं कि आप सवाल क्या चाहते हैं, बजाय इसके कि वास्तव में क्या पूछा जाता है। प्रश्न कुछ स्रोत कोड प्रदान करता है और पूछता है कि क्या यह वास्तविक जीवन C ++ कोड के रूप में एक अनंत लूप उत्पन्न करता है। नया खेल! एक काल्पनिक काम है; वास्तविक जीवन मानकों के अनुरूप इसमें प्रस्तुत कोड की कोई आवश्यकता नहीं है। Umiko कोड के बारे में क्या कहता है, किसी भी C ++ मानकों या संकलक की तुलना में अधिक आधिकारिक है। शीर्ष (स्वीकृत) उत्तर में किसी भी ब्रह्मांड जानकारी का उल्लेख नहीं है। मुझे लगता है कि इस विषय पर एक अच्छा जवाब के साथ सवाल पूछा जा सकता है, लेकिन जैसा कि यह है कि यह नहीं है।
कोड एक अनंत लूप नहीं है, लेकिन यह एक बग है।
दो (संभवतः तीन) मुद्दे हैं:
- यदि कोई डिब्यू मौजूद नहीं है तो कोई क्षति बिल्कुल भी लागू नहीं होगी
- 1 से अधिक डेब्यू होने पर अत्यधिक क्षति को लागू किया जाएगा
- यदि नष्ट () तुरंत वस्तु को हटा देता है और अभी भी m_debufs को संसाधित किया जाना है तो लूप को हटाए गए ऑब्जेक्ट पर निष्पादित किया जाएगा और मेमोरी को ट्रैश किया जाएगा। अधिकांश गेम इंजनों के पास इसके चारों ओर काम करने के लिए एक नष्ट कतार है और अधिक एक मुद्दा नहीं हो सकता है।
क्षति का आवेदन लूप के बाहर होना चाहिए।
यहाँ सुधारा गया कार्य है:
// 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 क्या हम कोड की समीक्षा पर हैं? : डी
- अगर आप 16777216 एचपी से ऊपर नहीं जाते हैं तो 4 तैरना स्वास्थ्य के लिए बहुत अच्छा है। आप दुश्मन को मारने के लिए अनंत तक स्वास्थ्य भी सेट कर सकते हैं, लेकिन आप मर नहीं सकते, और अनंत क्षति का उपयोग करके एक-एक हमला कर सकते हैं जो अभी भी एक अनंत एचपी चरित्र को नहीं मारेगा (INF-INF का परिणाम NaN है) लेकिन बाकी सब को मार देंगे। तो यह बहुत उपयोगी है।
- 1 @ cat कई कोडिंग मानकों में सम्मेलन द्वारा
m_
उपसर्ग का अर्थ है कि यह एक सदस्य चर है। इस मामले में एक सदस्य चरDestructibleActor
. - 2 @HotelCalifornia मैं मानता हूँ कि एक छोटा सा मौका है
ApplyToDamage
अपेक्षा के अनुसार काम नहीं करता है, लेकिन उदाहरण के मामले में आप मुझे बताएंगेApplyToDamage
भी इसे मूल रूप से पारित करने की आवश्यकता के लिए फिर से काम करने की आवश्यकता हैsourceDamage
साथ ही साथ यह उन मामलों में डेब्यू की ठीक से गणना कर सकता है। एक निरपेक्ष पेडेंट होने के लिए: इस बिंदु पर डीएमजी जानकारी एक ऐसी संरचना होनी चाहिए जिसमें मूल डीजीएम, करंट डीजीएम, और क्षति (एस) की प्रकृति के साथ-साथ अगर डेब्यू में "आग की चपेट में" जैसी चीजें शामिल हैं। अनुभव से यह डिफ्यूज़ की मांग के साथ किसी भी गेम डिज़ाइन से बहुत पहले नहीं है। - 1 @StephaneHockenhull अच्छी तरह से कहा!
कोड एक अनंत लूप बनाने के लिए नहीं लगता है।
लूप अनंत होने का एकमात्र तरीका होगा यदि
debuf.ApplyToDamage(resolvedDamage);
या
DestroyMe();
में नए आइटम जोड़ने थे m_debufs
कंटेनर।
यह संभव नहीं लगता है। और अगर ऐसा होता, तो पुनरावृत्त होने के दौरान कंटेनर को बदलने के कारण प्रोग्राम क्रैश हो सकता था।
कार्यक्रम की संभावना सबसे अधिक कॉल करने के कारण दुर्घटना होगी DestroyMe();
जो वर्तमान में वर्तमान में चल रही वस्तु को नष्ट कर देता है।
हम इसे कार्टून के रूप में सोच सकते हैं, जहां 'बुरे आदमी' के पास 'अच्छे आदमी' को देखने के लिए एक शाखा है, लेकिन यह बहुत देर से पता चलता है कि वह कट के गलत पक्ष पर है। या मिडगार्ड सांप खाने की अपनी पूंछ है।
मुझे यह भी जोड़ना चाहिए कि एक अनंत लूप का सबसे आम लक्षण यह है कि यह प्रोग्राम को जमा देता है या इसे उत्तरदायी नहीं बनाता है। यह प्रोग्राम को क्रैश कर देगा यदि यह बार-बार मेमोरी आवंटित करता है, या ऐसा कुछ करता है जो शून्य या पसंद के अनुसार विभाजित होता है।
अकी तनाका की टिप्पणी के आधार पर,
संभवतः मददगार: उमिको का अतिरिक्त स्क्रीनशॉट यह कहते हुए कि "यह बार-बार एक ही ऑपरेशन को कॉल कर रहा था", जो कोड में नहीं दिखाया जा सकता है।
"यह एक ही ऑपरेशन को बार-बार बुला रहा था" इसकी संभावना अधिक है।
ये मानते हुए DestroyMe();
एक से अधिक बार कॉल करने के लिए डिज़ाइन नहीं किया गया है, इससे दुर्घटना होने की संभावना अधिक है।
इस मुद्दे को ठीक करने का एक तरीका यह होगा कि इसे बदल दिया जाए if
कुछ इस तरह के लिए:
if (m_currentHealth <= 0.f) { m_currentHealth = 0.f; DestroyMe(); break; }
यह विनाशकारी ट्रैक्टर नष्ट हो जाने पर लूप से बाहर निकल जाएगा, यह सुनिश्चित करता है कि 1) द DestroyMe
विधि को केवल एक बार और 2 कहा जाता है) जब वस्तु पहले से ही मृत मानी जाती है तो बेकार को लागू न करें।
- 1 स्वास्थ्य के लिए लूप से बाहर निकलना जब स्वास्थ्य <= 0 निश्चित रूप से स्वास्थ्य की जांच करने के लिए लूप के बाद इंतजार करने से बेहतर निश्चित है।
- मुझे लगता है कि मैं शायद होता
break
लूप से बाहर, और तब फिर कॉलDestroyMe()
, बस सुरक्षित करने के लिए
कोड के साथ कई समस्याएं हैं:
- यदि कोई डीबफ नहीं हैं, तो कोई नुकसान नहीं होगा।
DestroyMe()
फ़ंक्शन नाम खतरनाक लगता है। इसके लागू होने के आधार पर, यह एक मुद्दा हो सकता है या नहीं भी हो सकता है। यदि यह किसी फ़ंक्शन में लिपटे वर्तमान ऑब्जेक्ट के विध्वंसक के लिए सिर्फ एक कॉल है, तो एक मुद्दा है, क्योंकि ऑब्जेक्ट कोड को निष्पादित करने के बीच में नष्ट हो जाएगा। यदि यह एक ऐसे फ़ंक्शन को कॉल करता है जो वर्तमान ऑब्जेक्ट के विलोपन घटना को कतार में रखता है, तो कोई समस्या नहीं है, क्योंकि इसके निष्पादन को पूरा करने के बाद ऑब्जेक्ट को नष्ट कर दिया जाएगा और इवेंट लूप में किक।- वास्तविक मुद्दा जो एनीमे में उल्लिखित प्रतीत होता है, "यह एक ही ऑपरेशन को बार-बार बुला रहा था" - यह कॉल करेगा
DestroyMe()
जब तकm_currentHealth <= 0.f
और अधिक डिटरफ़ेट को पुनरावृति के लिए छोड़ दिया गया है, जिसके परिणामस्वरूप हो सकता हैDestroyMe()
बार-बार, कई बार कहा जा रहा है। लूप को पहले के बाद बंद कर देना चाहिएDestroyMe()
कॉल, क्योंकि स्मृति भ्रष्टाचार में एक से अधिक बार एक वस्तु को हटाने, जिसके परिणामस्वरूप लंबे समय में दुर्घटना की संभावना होगी।
मुझे वास्तव में यकीन नहीं है कि प्रत्येक डेब्यू स्वास्थ्य को दूर ले जाता है, बजाय स्वास्थ्य को केवल एक बार दूर ले जाने के साथ, सभी डिफफ्यू के प्रभावों को प्रारंभिक क्षति पर लागू किया जा रहा है, लेकिन मुझे लगता है कि यह सही गेम लॉजिक है।
सही कोड होगा
// 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 - मुझे यह इंगित करना चाहिए कि जैसा कि मैंने अतीत में मेमोरी एलोकेटर लिखा है, उसी मेमोरी को हटाना एक मुद्दा नहीं है। यह बेमानी भी हो सकता है। यह सब आवंटनकर्ता के व्यवहार पर निर्भर करता है। मेरा सिर्फ एक निम्न स्तर की लिंक की गई सूची की तरह काम करता है इसलिए हटाए गए डेटा के लिए "नोड" या तो कई बार मुफ्त में सेट हो जाता है या कई बार फिर से डिलीट हो जाता है (जो कि केवल निरर्थक सूचक पुनर्निर्देशन के अनुरूप होगा)। हालांकि अच्छा कैच।
- डबल-फ्री एक बग है, और आमतौर पर अपरिभाषित व्यवहार और दुर्घटनाओं की ओर जाता है। यहां तक कि अगर आपके पास एक कस्टम आवंटनकर्ता है जो किसी भी तरह एक ही मेमोरी पते के पुन: उपयोग को अस्वीकार करता है, तो डबल-फ्री एक बदबूदार कोड है क्योंकि यह कोई मतलब नहीं है और आप स्थिर कोड विश्लेषक द्वारा चिल्लाए जाएंगे।
- बेशक! मैंने इसे उस उद्देश्य के लिए डिज़ाइन नहीं किया था। कुछ भाषाओं में सुविधाओं की कमी के कारण बस एक आवंटनकर्ता की आवश्यकता होती है। नहीं नहीं नहीं। मैं केवल यह कह रहा था कि एक दुर्घटना की गारंटी नहीं है। कुछ डिज़ाइन वर्गीकरण हमेशा क्रैश नहीं करते हैं।