Download Xray Engine 1.5. X-Ray Engine - קוד מקור

מנוע הרנטגן אינו ידוע למדי מחוץ למדינות חבר העמים, ומעטים מודדים מכירים אותו כאן, וזה לא מפתיע - רק 3 משחקים יצאו עליו. אבל כמעט כל גיימר מכיר את המשחקים האלה - זוהי טרילוגיית S.T.A.L.K.E.R., אחת מסדרות המשחקים האיכותיות הבודדות שיצאו במרחב הפוסט-סובייטי. זה התברר כל כך מרגש שמודים חדשים מופיעים אפילו עכשיו, 8 שנים לאחר השחרור. משחק אחרוןסדרה (Call of Pripyat, 2009). וחלק מהאופנים הפכו לאייקוניים, שינו את המשחק באופן קיצוני - הם הוסיפו בינה מלאכותית חכמה יותר, מכוניות, עוד כלי נשק, משימות סיפור חדשות ואפילו מיקומים. אבוי - המשך הסדרה, המשחק S.T.A.L.K.E.R. 2 הוקפא רשמית, אבל רבים מחכים לו בדיוק כמו Half-Life 3.

ההיסטוריה של הופעת המנוע

המנוע פותח לחלוטין על ידי אולפן המשחקים האוקראיני GSC Game World, המתכנתים Ales Shishkovtsov ו- Oleksandr Maksimchuk עבדו על החלק הגרפי של המנוע (הם עבדו גם על פרויקט Metro 2033 ב-4A Games). ההדגמה הראשונה של המנוע נערכה בשנת 2001:


כפי שניתן לראות, ה-S.T.A.L.K.E.R. זה אפילו לא היה קרוב - ההדגמה הייתה יותר כמו הג'ונגל של Far Cry 1. עם זאת, גם אז המנוע היה די מתקדם - הוא עבד על DirectX 7 (מאוחר יותר, נוספה תמיכה ב-DirectX 8 ו-9 לשחרור של Shadows של צ'רנוביל בשנת 2007), נתמך במיפוי פרטים, Lightmap , AI מתקדם ומרקמים ברזולוציה גבוהה - עד 4,000,000 מצולעים יכולים להיות במסגרת אחת. עם זאת, כדי שמחשבים של אז ימשכו את כל היופי הזה, גודל מיקום המשחק היה צריך להיות מוגבל מאוד - זה יכול להיות לא יותר מ-2 מטרים רבועים. ק"מ ונטען מיד ובשלמותו, אך היו מעברים בין מיקומים עם מסכי טעינה. X-Ray נכתב ב-C/C++ באמצעות מקורות Microsoft DirectX SDK, עם מהדר שפת LUA "lua.JIT.1.1.4" מצורף אליו. בזמן העבודה, הספריות Microsoft Visual C ++ 7.1, Creative EAX (טכנולוגיה ליצירת אפקטים קוליים סביבה), ODE (מנוע פיזיקה פתוח), OpenAL (ממשק תכנות יישומים (API) לעבודה עם נתוני אודיו, GameSpy Client (רכיב מרובה שחקנים) ו-Color Picker.

פיתוח מנוע

כמו כל פרויקט בנייה ארוך טווח, במהלך 6 השנים מרגע יציאת המנוע ועד להופעת המשחק הראשון בו, הוא רכש עוד ועוד "טובים" חדשים כמו:

  • תמיכה בכל מאיצי ה-D3D מהדור השלישי, מ-GeForce 2 ומעלה;
  • ויזואליזציה מותאמת לטכנולוגיית TnL (טרנספורמציה ותאורה - מנגנון הממיר אובייקט תלת מימדי ממסגרת ייחוס אחת לאחרת);
  • טכנולוגיית תאורה והצללה דחויים, המאפשרת להשיג נאמנות גבוהה בעיבוד תאורה עם מורכבות גיאומטרית גבוהה של הסצנה;
  • טכנולוגיית רמת פירוט מתקדמת לכל הגיאומטריה;
  • דמויות וכלי נשק מפורטים מאוד;
  • מערכת אנימציה מעורבת במהירות גבוהה המסוגלת למספר בלתי מוגבל של אינטרפולציה של עצמות ופעולות מודולריות;
  • תמיכה עבור SSE/3Dnow! טכנולוגיות עבור מעבדי אינטלו-AMD, בהתאמה, המאפשרים לך לייעל את העומס עליהם;
  • מערכת נראות לא ליניארית מבוססת פורטל;
  • טכנולוגיות חיסום/תרומה דינמיות (השבתת העיבוד של אובייקטים שנמצאים מחוץ למצלמה או במרחק רב);
  • טכנולוגיית מטמון הניתנת להתאמה לחומרה;
  • תאורה דינמית צבעונית וצללים "רכים" דינמיים;
  • מקורות אור מונפשים הניתנים להרס;
  • בחירת מקור אור מתקדם, מיזוג ופיצול, הטלת צללים לפי דמויות;
  • מערכת חלקיקים עם פיזיקה אמיתית;
  • מערכת הצללה מתקדמת;
  • שינוי דינמי של מזג האוויר, ביום ובלילה.
X Ray Engine 1.0

למשחק היחיד במנוע הזה, Shadows of Chernobyl, היו בתחילה שני ממשקי API לבחירה בהגדרות - DirectX 8 עם התכונות שתוארו לעיל, ו-DirectX 9, שמוסיף עוד כמה אפקטים גרפיים:
  • עיבוד נקודה צפה בטווח דינמי גבוה (HDR);
  • מיפוי בליטות, מיפוי רגיל ומיפוי פרלקסה ( סוגים שוניםמרקם הקלה);
  • תאורה דינמית לחלוטין, צללים רכים;
  • עומק שדה (עומק שדה), טשטוש תנועה (טשטוש בתנועה), בלום (טשטוש אור בקצוות האובייקט) וקרני אור דינמיות.
המשחק, למרות שזה היה בנייה לטווח ארוך, התברר כטוב מבחינת גרפיקה, בעיקר בשל האובייקטים הפוטוריאליסטיים של האזור (המפתחים הלכו ל-ChEZ מספר פעמים כדי לצלם תמונות):




חיים

תכונה נוספת של המנוע שמפתחים יכולים להתגאות בה היא מערכת הבינה המלאכותית A-Life (חיים מלאכותיים). המפתחים עצמם מתארים זאת כך:

השורה התחתונה היא שהדמויות במשחק חיות את חייהן וקיימות כל הזמן, ולא רק כשהשחקן רואה אותן. [...] הצגנו שני מונחים המאפיינים 2 מודלים של התנהגות אופי הנבדלים במידת הפירוט: לא מקוון ומקוון. ההתנהגות הלא מקוונת של הדמות פשוטה מאוד מבחינת פירוט: הדמות לא משחקת אנימציות, קולות, לא מנהלת מלאי באופן אקטיבי, לא בונה נתיבים מוחלקים מפורטים (למרות שהיא בונה נתיבים לפי גרף הניווט הגלובלי, אבל על כך בהמשך ), וכו. להתנהגות מקוונת, לעומת זאת, יש פירוט מלא. הָהֵן. ניתן לשקול שהתנהגות לא מקוונת היא פרי התנהגות מקוונת.

במערכת שלנו, בזמן שהשחקן משחק ברמה שלו, דמויות אחרות חיות ברמות אחרות, כלומר. נמצאים במצב לא מקוון, כלומר. להשתמש בהתנהגות לא מקוונת. יתרה מכך, בגלל האוכלוסייה הגדולה, לא לכל הדמויות באותה רמה יש התנהגות מקוונת, אלא רק לאלה שנמצאות ברדיוס נתון מהשחקן (זה עשוי להיות תלוי ברמות, בדרך כלל בסביבות 150 מטר) או לפי בקשת המשחק מעצבים.

כדי ליישם זאת, הסימולטור עוקב אחר תנועת השחקן והאובייקטים במצב לא מקוון ומתרגם אותם לאונליין / לא מקוון. בעת חישוב המעבר של אובייקטים, נעשה שימוש בטריק סטנדרטי עם אינרציה: רדיוס המעבר הלא מקוון גדול יותר מרדיוס המעבר המקוון.

לאחר מכן, ראוי להזכיר את הניווט של אובייקטים באינטרנט ובאופן לא מקוון. יש לנו רמות במשחק, שלכל אחת מהן נוצר גרף ניווט, שדמויות משתמשות בו כדי לנוע באינטרנט. אנחנו קוראים לזה גרף מפורט. עבור כל גרף מפורט נוצר גם האנלוג הפחות מפורט שלו, שאת קודקודיו ניתן לחבר עם קודקודי אותו גרף ברמה/ים אחרת. הָהֵן. לאחר שילוב כל הגרפים הללו יחד, נקבל גרף המשלב את כל הרמות. הוא משמש את הדמויות כדי לעבור לא מקוון. זה משמש גם על ידי דמויות מקוונות כשהן מבצעות את שלהן יעדים אסטרטגיים. לדוגמה, אם דמות מקוונת מחליטה ללכת לרמה אחרת, אז הוא בונה נתיב לאורך הגרף הגלובלי, ואז בונה נתיב לאורך הגרף המפורט של הרמה שלו מהמיקום שלו לנקודת הגרף הגלובלי. אם הנקודה הזו כבר נמצאת ברמה אחרת, אז הוא מבצע טלפורטציה לשם ועובר אוטומטית למצב לא מקוון. כדי למנוע את זה מתרחש מול השחקן, הגדרנו את נקודות המעבר לדמויות המשחק יותר מנקודות המעבר של השחקן, אי שם "מעבר לפינה"

כפי שאתה יכול לראות, ה-AI איכותי מאוד, ולאורך כל המשחק אין תחושה שה-Zone מת - כמה אירועים מתרחשים כל הזמן: יריות, מפגש עם סטוקרים שונים, מוטנטים, הופעת הודעות חדשות ב-PDA , וכו.

מנוע רנטגן 1.5

שנה לאחר מכן, לאחר יציאתו של Shadows of Chernobyl, בשנת 2008, יצא חלק חדש במשחק, Clear Sky. למשחק נוספו כלי נשק ומיקומים חדשים, כמו גם תמיכה ב-API חדש - DirectX 10. זה שיפר משמעותית את איכות המים והחלקיקים, כמו גם הוספת תמיכה למשטחים רטובים (כלומר, המשטח נראה אחרת לפני ואחרי גשם) ומיפוי פרלקס תלול (תצוגה מציאותית של עצמים בולטים על מרקם שטוח - למשל, אבנים בולטות בקיר). אבל באופן כללי, הגרפיקה הייתה ברמה של החלק הקודם של המשחק:


מנוע רנטגן 1.6

בחלק האחרון של הטרילוגיה, Call of Pripyat, שיצא ב-2009, המנוע קיבל תמיכה ב-DirectX 11. עם זאת, למרבה הצער, המנוע בן ה-8 לא משך את כל התכונות שלו, כך שנוספו רק טסל (התהליך של הוספת מצולעים קמורים חדשים לרשת מצולעת על מנת להגדיל את פירוט הרשת, במילים אחרות, עצמים קמורים הפכו למציאותיים יותר). רמה כלליתהגרפיקה נשארה זהה:


מנוע פיזיקה

X-Ray משתמש במנוע הפיזיקה החופשי Open Dynamics Engine (ODE). התכונות שלו:

  • עיבוד התנגשות במהירות גבוהה (מהיר יותר מ- MathEngine מסחרי, Havok וכו'), זיהוי התנגשות מותאם עבור מספר גדולבקשות בסביבת פולי גבוה;
  • הדמיה ריאליסטית של בליסטיקה, תנועה, פיזיקת מכוניות וכו'.
מנוע רנטגן 2

העוקב. 2 על מנוע רנטגן 2 הוכרז באוגוסט 2010, המשחק היה אמור לצאת בשנת 2012. עם זאת, בדצמבר 2011, פיתוח המשחק הופסק, וטרם נמשך, למרות שאולפן המשחקים GSC שמפתח את המשחק עדיין קיים - ב בספטמבר 2016, הוא הוציא את המשחק Cosacks 3. ידוע שבזמן שהפרויקט הוקפא, המנוע היה מוכן ב-70-80%, ונעשו גם כמה רמות ודמויות של משחק. המשחק היה אמור להיות עולם חלק, ומנוע הפיזיקה היה Havok. בהתחשב בגיל ההתפתחות של S.T.A.L.K.E.R. סביר להניח ש-2 לא ישוחרר לעולם, ויהפוך לפרויקט "נצחי" כמו Half-Life 3.

X-Ray Engine היא שפת תכנות שנוצרה על ידי GSC Game World עבור שימוש פנימי. כל מי ששיחק במשחק המחשב Stalker שמע על החברה הזו. מנוע ה-SDK (ערכת פיתוח תוכנה) הרשמי וקוד המקור לשפת התכנות של המשחק משמשים את יוצרי המודים הלא רשמיים.

בתהליך יצירת Stalker - Shadow of Chernobyl, המפתחים השתמשו ב-X-Ray, וגם הוציאו שתי גרסאות של המשחק שהמשיכו את המקור: Clear Sky ו-Call of Pripyat. גרסה שונה של ה"מנוע" שימשה ליצירת פרויקט Stalker 2, אך הפיתוח נעצר כבר ב-2011.

מַטָרָה

מפתחי משחקים משתמשים במנוע ה-X-Ray כדי ליצור אופנים חדשים. Stalker הוא משחק מרובה חלקים, אשר שוחררו לו הרבה שינויים. כדי לעזור למפתחי מודים, GSC Game World יצרה כלי SDK. מודים רבים שוחררו לכל חלק במשחק עם איכות גרפית ושינויים שונים.

יוצרי המנוע הייחודי שכחו "לאשר" אותו במסמכים רשמיים. המפתחים הראשונים של מודים יצרו אותם חצי אפויים. במהלך הפיתוח של המודים הראשונים וכתיבת סקירה זו, היו הרבה הוראות ופורומים נושאיים. הודות להוראות אלה, אנשים מתקשרים ומשתפים את החוויה שלהם עם ה-SDK.

מפרטים

הגרסה הסופית של המנוע פועלת על כלי אבחון וספריית DirectX 11. לשפת התכנות יש תמיכה באור נפחי ובאפקטי עשן מורכבים, והיא גם מאפשרת לרנדר סצנות משחק מורכבות ועובדת עם פיזיקת Ragdoll.

בגרסה הראשונה של שפת התכנות, המפתחים הוסיפו צללים רכים למשחק. בזמן יציאת החלק הראשון של המשחק, אלמנט גרפי כזה היה משהו חדש ומעניין מבחינה טכנית, במיוחד עבור משחק עם חלל גדול ושטח פתוח.

תכונות עיקריות

  • SDK רשמי ליוצרי מפות ששונו למשחק;
  • שפת התכנות תומכת בספריות DirectX 11;
  • יצירת פיזיקה עם תנועה מציאותית ומערכת AI משלו (A-Life);
  • הכנסת טכנולוגיה היוצרת טקסטורות תבליט של חפצים;
  • תמיכה בצללים רכים ואור נפחי;
  • הצגת כארבעה מיליון מצולעים במסגרת אחת;
  • שפת התכנות של המשחק אינה מאושרת ואינה מופצת רשמית;
  • ציור סצנות משחק מורכבות ותמיכה בפיזיקה של הדור הבא.
X-Ray נוצר על ידי חברת GSC GameWorld האוקראינית עבור המשחק S.T.A.L.K.E.R.: Shadow of Chernobyl. המנוע כולל רינדור עם תמיכה ב-DirectX 8.1/9.0c/10/10.1/11, מנועי פיזיקה וסאונד, מרובה משתתפים ומערכת בינה מלאכותית A-Life. בהמשך יצרה החברה מנוע גרסה 2.0 למשחק החדש שלה, אך הפיתוח הופסק וקודי המקור דלפו לרשת.

הפרויקט, יחד עם כל התלות שלו, מורכב בקלות ב-Visual Studio 2015. לצורך אימות, השתמשנו בקוד המקור של גירסת המנוע 1.6 מהמאגר ב-GitHub ובמנתח הקוד הסטטי PVS-Studio 6.04, אותו ניתן להוריד מ- הקישור .

העתק הדבק

ראשית, בואו נסתכל על השגיאות הקשורות להעתקת הקוד. התרחיש של התרחשותם ב הזדמנויות שונותבדרך כלל דומה: הם העתיקו את הקוד, שינו חלק מהמשתנים ושכחו כמה. באגים כאלה יכולים להתפשט במהירות דרך בסיס הקוד, וללא מנתח סטטי, קל מאוד לפספס אותם.

MxMatrix& MxQuadric::homogeneous(MxMatrix& H) const ( .... unsigned int i, j; for(i=0; i אזהרת PVS-Studio: V533 סביר להניח שמשתנה שגוי מוגדל בתוך האופרטור "for". שקול לסקור את "i". mxqmetric.cpp 76

המנתח זיהה זאת בלולאה המקוננת להמשתנה מוגדל אני, והמשתנה מסומן י, מה שמביא ללולאה אינסופית. סביר להניח, בעת העתקתו, הם פשוט שכחו לשנות אותו.
void CBaseMonster::settings_read(CInifile const * ini, LPCSTR section, SMonsterSettings &data) ( .... if (ini->line_exist(ppi_section,"color_base")) sscanf(ini->r_string(ppi_section,"color_base"), if (ini->line_exist(ppi_section,"color_base")) sscanf(ini->r_string(ppi_section,"color_grey"), "%f,%f,%f", &data.m_attack_effector.ppi.color_gray.r, &data .m_attack_effector.ppi.color_gray.g , &data.m_attack_effector.ppi.color_gray.b); if (ini->line_exist(ppi_section,"color_base")) sscanf(ini->r_string(ppi_section,"color_add"), "% f,%f,%f" , &data.m_attack_effector.ppi.color_add.r, &data.m_attack_effector.ppi.color_add.g, &data.m_attack_effector.ppi.color_add.b); .... )
אזהרות PVS-Studio:

  • V581 הביטויים המותנים של האופרטורים "אם" הממוקמים זה לצד זה זהים. קווי בדיקה: 445, 447. base_monster_startup.cpp 447
  • V581 הביטויים המותנים של האופרטורים "אם" הממוקמים זה לצד זה זהים. קווי בדיקה: 447, 449. base_monster_startup.cpp 449
בפרגמנט זה נעשה שימוש בכמה ביטויים מותנים זהים בשורה. ברור שצריך להחליף אותו color_baseעַל צבע_אפורו color_addלפי הקוד בגוף אםענפים .
/* לעבד משפט יחיד */ static void ProcessStatement(char *buff, int len) ( .... if (strncmp(buff,"\\pauthr\\",8) == 0) ( ProcessPlayerAuth(buff, len ); ) else if (strncmp(buff,"\\getpidr\\",9) == 0) ( ProcessGetPid(buff, len); ) else if (strncmp(buff,"\\getpidr\\",9) == 0) ( ProcessGetPid(buff, len); ) else if (strncmp(buff,"\\getpdr\\",8) == 0) ( ProcessGetData(buff, len); ) else if (strncmp(buff, "\\setpdr\\",8) == 0) ( ProcessSetData(buff, len); ) )
אזהרת PVS-Studio: V517 זוהה השימוש בתבנית "אם (A) (...) אחרת אם (A) (...)". קיימת סבירות לנוכחות שגיאה לוגית. קווי בדיקה: 1502, 1505. gstats.c 1502

כמו בדוגמה הקודמת, כאן נעשה שימוש בשני תנאים זהים ( strncmp(buff,"\\getpidr\\",9) == 0). קשה לומר בוודאות אם זה באג או סתם קוד בלתי ניתן להשגה, אבל בהחלט שווה לבדוק. יתכן שצריכים להיות בלוקים עם getpidr/setpidrבאנלוגיה עם getpdr/setpdr.
class RGBAMipMappedCubeMap ( .... size_t height() const ( return cubeFaces.height(); ) size_t width() const ( return cubeFaces.height(); ) .... );
אזהרת PVS-Studio: V524 זה מוזר שגוף הפונקציה "רוחב" שווה ערך לחלוטין לגוף הפונקציה "גובה". tpixel.h 1090

שיטות גוֹבַה()ו רוֹחַב()בעלי אותו גוף. בהתחשב בכך שממדי פני הקוביה מחושבים, ייתכן שלא תהיה כאן שגיאה. אבל עדיף לשכתב את השיטה רוֹחַב()בצורה הבאה:
size_t width() const ( return cubeFaces.width(); )

שימוש לרעה ב-C++

C++ היא שפה נפלאה שנותנת למתכנת הרבה אפשרויות... לירות לעצמו ברגל בצורה אכזרית במיוחד. התנהגות לא מוגדרת, דליפות זיכרון וכמובן שגיאות הקלדה – שגיאות מסוג זה יידונו בסעיף הנוכחי.

תבנית struct _matrix33 (ציבורי: typedef _matrix33 עצמי; typedef Self& SelfRef; .... IC SelfRef sMTxV(Tvector& R, float s1, const Tvector& V1) const ( R.x = s1*(m * V1.x + m * V1.y + m * V1.z); R.y = s1*(m * V1.x + m * V1.y + m * V1.z); R.z = s1*(m * V1.x + m * V1.y + m * V1.z); ) .... )
אזהרת PVS-Studio: V591 פונקציה Non-void אמורה להחזיר ערך. _matrix33.h 435

חסר בסוף השיטה להחזיר *זה. על פי התקן, קוד כזה יוביל להתנהגות לא מוגדרת. מכיוון שערך ההחזרה הוא הפניה, סביר להניח שהדבר תקרוס את התוכנית בעת ניסיון לגשת לערך ההחזרה.
ETOOLS_API int __stdcall ogg_enc(....) ( .... FILE *in, *out = NULL; .... input_format *format; .... in = fopen(in_fn, "rb"); if(in == NULL) החזר 0; format = open_audio_file(in, &enc_opts); if(!format)( fclose(in); return 0; ); out = fopen(out_fn, "wb"); if(out == NULL) ( fclose(out); return 0; ) .... )
אזהרת PVS-Studio: V575 מצביע האפס מועבר לפונקציה "fclose". בדוק את הטיעון הראשון. ogg_enc.cpp 47

דוגמה מעניינת למדי. המנתח זיהה שהטיעון בשיחה לסגורשווים nullptr, מה שהופך את הקריאה לפונקציה חסרת טעם. אפשר להניח שהם היו צריכים לסגור את הנחל ב.
void NVI_Image::ABGR8_To_ARGB8() ( // מחליף RGB עבור כל הפיקסלים assert(IsDataValid()); assert(GetBytesPerPixel() == 4); UINT hxw = GetNumPixels(); עבור (UINT i = 0; i< hxw; i++) { DWORD col; GetPixel_ARGB8(&col, i); DWORD a = (col >> 24) && 0x000000FF; DWORD b = (קול >> 16) && 0x000000FF; DWORD g = (קול >> 8) && 0x000000FF; DWORD r = (col >> 0) && 0x000000FF; col = (א<< 24) | (r << 16) | (g << 8) | b; SetPixel_ARGB8(i, col); } }
אזהרות PVS-Studio:

  • V560 חלק מביטוי מותנה תמיד נכון: 0x000000FF. nvi_image.cpp 170
  • V560 חלק מביטוי מותנה תמיד נכון: 0x000000FF. nvi_image.cpp 171
  • V560 חלק מביטוי מותנה תמיד נכון: 0x000000FF. nvi_image.cpp 172
  • V560 חלק מביטוי מותנה תמיד נכון: 0x000000FF. nvi_image.cpp 173
בקטע זה של קוד, פעולות לוגיות ופעולות סיביות מתערבבות. התוצאה לא תהיה מה שהמתכנת ציפה: קולתמיד יהיה 0x01010101 ללא קשר לקלט.

אפשרות נכונה:
DWORD a = (קול >> 24) & 0x000000FF; DWORD b = (קול >> 16) & 0x000000FF; DWORD g = (קול >> 8) & 0x000000FF; DWORD r = (col >> 0) & 0x000000FF;
דוגמה נוספת לקוד מוזר:
VertexCache::VertexCache() ( VertexCache(16); )
אזהרת PVS-Studio: V603 האובייקט נוצר אך אינו בשימוש. אם ברצונך לקרוא לבנאי, יש להשתמש ב-"this->VertexCache::VertexCache(....)". vertexcache.cpp 6

במקום לקרוא לבנאי אחד מהאחר כדי לאתחל את המופע, אובייקט חדש מסוג מטמון קודקוד. כתוצאה מכך, האיברים של האובייקט שנוצר יישארו לא מאותחלים.
BOOL CActor::net_Spawn(CSE_Abstract* DC) ( .... m_States.empty(); .... )
אזהרת PVS-Studio: V530 יש להשתמש בערך ההחזר של הפונקציה "ריק". actor_network.cpp 657

המנתח מזהיר שהערך המוחזר על ידי הפונקציה אינו בשימוש. נראה שהמתכנת פישל בשיטות ריק()ו ברור(): ריק()לא מנקה את המערך, אבל בודק אם הוא ריק.

שגיאות כאלה מתרחשות לעתים קרובות בפרויקטים שונים. הבעיה היא שהשם ריק()לא מובן מאליו: יש שתופסים את זה כפעולה - הסרה. כדי למנוע אי בהירות כזו, עדיף להוסיף את הפעלים יש, הוא לתחילת השיטה: אכן, זה ריק()עם ברור()קשה לבלבל.

אזהרה דומה:

V530 נדרש להשתמש בערך ההחזר של הפונקציה "ייחודי". uidragdroplistex.cpp 780
size_t xrDebug::BuildStackTrace(EXCEPTION_POINTERS* exPtrs, char *buffer, size_t capacity, size_t lineCapacity) ( memset(buffer, capacity*lineCapacity, 0); .... )
אזהרת PVS-Studio: V575 הפונקציה "memset" מעבדת אלמנטים של "0". בדוק את הטיעון השלישי. xrdebug.cpp 104

כשמתקשרים memsetהטיעונים מתערבבים וכתוצאה מכך המאגר לא מאופס לאפס, כפי שהתכוונו במקור. שגיאה כזו יכולה לחיות בפרויקט במשך זמן רב מאוד, מכיוון שקשה מאוד לזהות אותה. במקומות כאלה, מנתח סטטי בא לעזרתו של מתכנת.

שימוש נכון memset:
memset(buffer, 0, capacity*lineCapacity);
השגיאה הבאה קשורה לביטוי לוגי מורכב שגוי.
void configs_dumper::dumper_thread(void* my_ptr) ( .... DWORD wait_result = WaitForSingleObject(this_ptr->m_make_start_event, INFINITE); while (wait_result != WAIT_ABANDONED) ...| (wait)WAIT_result .AI=)
אזהרת PVS-Studio: V547 הביטוי הוא תמיד נכון. כנראה יש להשתמש באופרטור "&&" כאן. configs_dumper.cpp 262

ביטויים כמו "x != a || x != b" הם תמיד נכונים. סביר להניח, במקום האופרטור || האופרטור && היה מרומז.

תוכל לקרוא עוד על שגיאות בביטויים לוגיים במאמר "ביטויים לוגיים ב-C/C++. איך אנשי מקצוע עושים טעויות".
void SBoneProtections::reload(const shared_str& bone_sect, IKinematics* kinematics) ( .... CInifile::Sect &protections = pSettings->r_section(bone_sect); עבור (CInifile::SectCIt i=protections.Data.begin(); .Data.end() != i; ++i) ( string256 buffer; BoneProtection BP; .... BP.BonePassBullet = (BOOL) (atoi(_GetItem(i->second.c_str(), 2, buffer) )>0.5f); .... ) )
אזהרת PVS-Studio: V674 ה-"0.5f" מילולי מסוג "float" מושווה לערך מסוג "int". boneprotection.cpp 54

המנתח זיהה השוואה של ערך מספר שלם עם קבוע אמיתי. ייתכן שכאן, באנלוגיה, היה צריך להשתמש בפונקציה אטופ, אבל לא atoi, אחרת כדאי לשכתב את ההשוואה הזו כדי שהיא לא תיראה חשודה. עם זאת, רק המפתח שכתב את זה יכול לדעת בוודאות אם הדוגמה הזו שגויה או לא.
class IGameObject: Public Virtual IFactoryObject, Public Virtual ISpatial, Public Virtual ISheduled, Public Virtual IRenderable, Public Virtual ICollidable (public: .... Virtual u16 ID() const = 0; .... ) BOOL CBulletManager::test_callback(const collide::ray_defs& rd, אובייקט IGameObject*, פרמטרים LPVOID) ( bullet_test_callback_data* pData = (bullet_test_callback_data*) params; SBullet* bullet = pData->pBullet; if((object->ID() ==_id) bullet &&> (כדור->מרחק_זבוב flags.ricochet_was)) החזר FALSE; BOOL bRes = TRUE; if (object)( .... ) return bRes; )
אזהרת PVS-Studio: V595 נעשה שימוש במצביע ה"אובייקט" לפני שהוא אומת כנגד nullptr. קווי בדיקה: 42, 47. level_bullet_manager_firetrace.cpp 42

בדיקת מצביע לְהִתְנַגֵדלמען שוויון nullptrמגיע לאחר דחוי object->ID(). במקרה מתי לְהִתְנַגֵדהוא nullptr, זה יקרוס את התוכנית.
#ifdef _EDITOR BOOL WINAPI DllEntryPoint(....) #else BOOL WINAPI DllMain(....) #endif ( switch (ul_reason_for_call) ( .... case DLL_THREAD_ATTACH: if (!strstr(GetCommandLine(), "-editor ")) CoInitializeEx(NULL, COINIT_MULTITHREADED); timeBeginPeriod(1); break; .... ) return TRUE; )
אזהרת PVS-Studio: V718 אין לקרוא לפונקציה "CoInitializeEx" מהפונקציה "DllMain". xrcore.cpp 205

בגוף DllMainאינך יכול להשתמש בחלק מפונקציות WinAPI, כולל CoInitializeEx.אתה יכול לאמת זאת על ידי קריאת תיעוד MSDN. אי אפשר לתת עצה חד משמעית כיצד לשכתב את הפונקציה הזו, אבל כדאי להבין שמצב כזה הוא מסוכן, מכיוון שהוא יכול להוביל למבוי סתום או להתרסקות.

טעויות בסדרי עדיפויות

int sgetI1(לא סימן char **bp) ( int i; if (flen == FLEN_ERROR) return 0; i = **bp; if (i > 127) i -= 256; flen += 1; *bp++; return i ;)
אזהרת PVS-Studio: V532 שקול לבדוק את ההצהרה של דפוס "*pointer++". התכוון כנראה: "(*מצביע)++". lwio.c 316

השגיאה קשורה לשימוש בתוספת. למען הבהירות, אנו משכתבים את הביטוי הזה, וממקמים סוגריים:
*(bp++);
כלומר, תהיה תזוזה של אי תוכן בכתובת bp,אלא המצביע עצמו, שהוא חסר משמעות בהקשר הזה. מתחת לקוד יש קטעים של הטופס *bp += N, ולכן הגעתי למסקנה שזו טעות.

מיקום הסוגריים יעזור למנוע שגיאה כזו, שתהפוך את סדר החישובים למובנה יותר. גם טכניקה טובה היא להשתמש constלטיעונים שלא צריכים להשתנות.

אזהרות דומות:

  • V532 שקול לבדוק את ההצהרה של דפוס "*pointer++". התכוון כנראה: "(*מצביע)++". lwio.c 354
  • V532 שקול לבדוק את ההצהרה של דפוס "*pointer++". התכוון כנראה: "(*מצביע)++". lwob.c 80
void CHitMemoryManager::load (IReader &packet) ( .... if (!spawn_callback || !spawn_callback->m_object_callback) if(!g_dedicated_server) Level().client_spawn_manager().add(delayed_object.m_object_id,m_object_id, ),callback); #ifdef DEBUG else ( if (spawn_callback && spawn_callback->m_object_callback) ( VERIFY(spawn_callback->m_object_callback == callback); ) ) #endif // DEBUG )
אזהרת PVS-Studio: V563 ייתכן שענף "אחר" זה חייב לחול על הצהרת "אם" הקודמת. hit_memory_manager.cpp 368

בקטע הזה, הסניף אַחֵרשייך לשני אםבשל האסוציאטיביות הימנית שלו, שאינה זהה לעיצוב קוד. למרבה המזל, מקרה זה אינו משפיע על פעולת התוכנית, עם זאת, זה יכול לסבך את תהליך איתור באגים ובדיקה.

ההמלצה פשוטה - מניחים פלטה מתולתלת בענפים מורכבים יותר או פחות.
void HUD_SOUND_ITEM::PlaySound(HUD_SOUND_ITEM& hud_snd, const Fvector& position, const IGameObject* אב, bool b_hud_mode, bool looped, u8 index) ( .... hud_snd.m_activeSnd->snd.set_volume(hudactive_sndhudmode *volume_sndhudmode) psHUDSoundVolume:1.0f); )
אזהרת PVS-Studio: V502 אולי האופרטור "?:" פועל בצורה שונה ממה שהיה צפוי. לאופרטור "?:" יש עדיפות נמוכה יותר מאופרטור "*". hudsound.cpp 108

לאופרטור המותנה המשולש יש עדיפות נמוכה יותר מכפל, ולכן סדר הפעולות הוא:
(hud_snd.m_activeSnd->volume * b_hud_mode)?psHUDSoundVolume:1.0f
ברור שהקוד הנכון צריך להיראות כך:
hud_snd.m_activeSnd->volume * (b_hud_mode?psHUDSoundVolume:1.0f)
ביטויים המכילים אופרטור שליש הם מרובים אחרתענפים או פעולות AND / OR הם המקרים שבהם עדיף לשים סוגריים נוספים.

אזהרות דומות:

  • V502 אולי האופרטור "?:" עובד בצורה שונה ממה שהיה צפוי. לאופרטור "?:" יש עדיפות נמוכה יותר מאופרטור "+". uihudstateswnd.cpp 487
  • V502 אולי האופרטור "?:" עובד בצורה שונה ממה שהיה צפוי. לאופרטור "?:" יש עדיפות נמוכה יותר מאופרטור "+". uicellcustomitems.cpp 106

השוואות נוספות

void CDestroyablePhysicsObject::OnChangeVisual() ( if (m_pPhysicsShell)( if(m_pPhysicsShell)m_pPhysicsShell->Deactivate(); .... ) .... )
אזהרת PVS-Studio: V571 בדיקה חוזרת. התנאי "if (m_pPhysicsShell)" כבר אומת בשורה 32. destroyablephysicsobject.cpp 33

דוגמה זו בודקת פעמיים m_pPhysicsShell. סביר להניח שהבדיקה השנייה מיותרת.
void CSE_ALifeItemPDA::STATE_Read(NET_Packet &tNetPacket, גודל u16) ( .... if (m_wVersion > 89) if ((m_wVersion > 89)&&(m_wVersion< 98)) { .... }else{ .... } }
אזהרת PVS-Studio: V571 בדיקה חוזרת. התנאי "m_wVersion > 89" כבר אומת בשורה 987. xrserver_objects_alife_items.cpp 989

קוד מוזר מאוד. האם שכחו את הביטוי כאן אחר כך if (m_wVersion > 89)או סדרה שלמה אחרת-אם. שיטה זו דורשת התייחסות מפורטת יותר של מפתח הפרויקט.
void ELogCallback(void *context, LPCSTR txt) ( .... bool bDlg = ("#"==txt)||((0!=txt)&&("#"==txt)); if (bDlg) ( int mt = ("!"==txt)||((0!=txt)&&("!"==txt))?1:0; .... ) )
אזהרות PVS-Studio:

  • V590 שקול לבדוק את הביטוי "(0 != txt) && ("#" == txt)". הביטוי מוגזם או מכיל טעות הדפסה. elog.cpp 29
  • V590 שקול לבדוק את הביטוי "(0 != txt) && ("!" == txt)". הביטוי מוגזם או מכיל טעות הדפסה. elog.cpp 31
בביטויי אתחול משתנים bDlgו הרבְּדִיקָה (0 != txt)הוא מיותר. אם תשמיט אותו, הביטויים יהפכו להרבה יותר קלים לקריאה:
bool bDlg = ("#"==txt)||("#"==txt); int mt = ("!"==txt)||("!"==txt)?1:0;

שגיאות בסוגי נתונים


Float CRenderTarget::im_noise_time; CRenderTarget::CRenderTarget() ( .... param_blur = 0.f; param_gray = 0.f; param_noise = 0.f; param_duality_h = 0.f; param_duality_v = 0.f; param_noise_fps = _1noise_scale param .f; im_noise_time = 1/100; im_noise_shift_w = 0; im_noise_shift_h = 0; .... )
אזהרת PVS-Studio: V636 הביטוי "1/100" נוצק באופן מרומז מסוג "int" לסוג "float". שקול להשתמש בקאסט מסוג מפורש כדי למנוע אובדן של חלק חלקי. דוגמה: כפול A = (כפול)(X) / Y;. gl_rendertarget.cpp 245

הערך של הביטוי 1/100 הוא 0 מכיוון שמתבצעת פעולת חלוקת מספרים שלמים. כדי לקבל את הערך 0.01f, אתה צריך להשתמש מילולי אמיתי, לשכתב את הביטוי: 1/100.0f. למרות שייתכן שהתנהגות זו נועדה על ידי המחבר, ואין כאן טעות.
CSpaceRestriction::merge(....) const ( .... LPSTR S = xr_alloc (acc_length); for (; I != E; ++I) temp = strconcat(sizeof(S),S,*temp,",",*(*I)->name()); ....)
אזהרת PVS-Studio: V579 הפונקציה strconcat מקבלת את המצביע וגודלו כארגומנטים. ייתכן שזו טעות. בדוק את הטיעון הראשון. space_restriction.cpp 201

פוּנקצִיָה strconcat, לוקח את אורך המאגר כפרמטר הראשון. בַּלָם סהכריז כ LPSTR, כלומר, כמצביע למחרוזת. גודל של (S)יהיה שווה לגודל המצביע בבתים, כלומר. sizeof(char *), לא מספר התווים במחרוזת. כדי לחשב את האורך, השתמש strlen(S).
class XRCDB_API MODEL ( .... u32 status; // 0=ready, 1=init, 2=building .... ) void MODEL::build (Fvector* V, int Vcnt, TRI* T, int Tcnt, build_callback * bc, void* bcp) ( .... BTHREAD_params P = ( this, V, Vcnt, T, Tcnt, bc, bcp ); thread_spawn(build_thread,"CDB-construction",0,&P); while (S_INIT = = status) Sleep(5); .... )
אזהרת PVS-Studio: V712 שימו לב שהמהדר עשוי למחוק מחזור זה או להפוך אותו לאינסוף. השתמש במשתנים נדיפים או בפרימיטיבים של סנכרון כדי להימנע מכך. xrcdb.cpp 100

המהדר יכול להסיר את הסימון S_INIT == סטטוסכאופטימיזציה, שכן המשתנה סטָטוּסלא השתנה בלולאה. כדי להימנע מהתנהגות זו, עליך להשתמש נָדִיףמשתנים או סוגים של סנכרון נתונים בין שרשורים.

אזהרות דומות:

  • V712 שימו לב שהמהדר עשוי למחוק את המחזור הזה או להפוך אותו לאינסוף. השתמש במשתנים נדיפים או בפרימיטיבים של סנכרון כדי להימנע מכך. levelcompilerloggerwindow.cpp 23
  • V712 שימו לב שהמהדר עשוי למחוק את המחזור הזה או להפוך אותו לאינסוף. השתמש במשתנים נדיפים או בפרימיטיבים של סנכרון כדי להימנע מכך. levelcompilerloggerwindow.cpp 232
void CAI_Rat::UpdateCL() ( .... if (!Useful()) ( בירושה::UpdateCL (); Exec_Look (Device.fTimeDelta); CMonsterSquad *squad = monster_squad().get_squad(this); if (squad) && ((squad->GetLeader() != this && !squad->GetLeader()->g_Alive()) || squad->get_index(this) == u32(-1))) squad->SetLeader(this ); .... ) .... )
אזהרת PVS-Studio: V547 ביטוי "squad->get_index(this) == u32(- 1)" הוא תמיד שקר. טווח הערכים של סוג תווים ללא סימן: . ai_rat.cpp 480

על מנת להבין מדוע הביטוי הזה תמיד שקרי, הבה נחשב את הערכים של האופרנדים הבודדים. u32(-1) הוא 0xFFFFFFFF או 4294967295. הסוג המוחזר על ידי השיטה squad->get_index(....), - u8, כך שהערך המקסימלי שלו הוא 0xFF או 255, שזה בהחלט פחות מ-u32(-1). בהתאם, ערכה של השוואה כזו תמיד יהיה שֶׁקֶר. קל לתקן את הקוד הזה על ידי שינוי סוג הנתונים ל-u8:
squad->get_index(this) == u8(-1)
אותו אבחון עובד עבור השוואות מיותרות של משתנים ללא סימנים:
מרחב השמות ALife ( typedef u64 _TIME_ID; ) ALife::_TIME_ID CScriptActionCondition::m_tLifeTime; IC bool CScriptEntityAction::CheckIfTimeOver() ( return((m_tActionCondition.m_tLifeTime >= 0) && ((m_tActionCondition.m_tStartTime + m_tActionCondition.m_tLifeTime)< Device.dwTimeGlobal)); }
אזהרת PVS-Studio: V547 ביטוי "m_tActionCondition.m_tLifeTime >= 0" הוא תמיד נכון. ערך הסוג הלא חתום הוא תמיד >= 0. script_entity_action_inline.h 115

מִשְׁתַנֶה m_tLifeTimeהוא ללא סימן, אז הוא תמיד גדול או שווה לאפס. אם זו בדיקה נוספת או שגיאה בלוגיקה מוסתרת כאן, זה תלוי המפתח לשפוט.

אזהרה דומה:

V547 ביטוי "m_tActionCondition.m_tLifeTime< 0" is always false. Unsigned type value is never < 0. script_entity_action_inline.h 143
ObjectFactory::ServerObjectBaseClass * CObjectItemScript::server_object (קטע LPCSTR) const ( ObjectFactory::ServerObjectBaseClass *object = nullptr; try ( object = m_server_creator(section); ) catch(std::exception e) ( Msg("Exception ] הועלה בעת יצירת אובייקט שרת מ- " "מקטע [%s]", e.what(),section); return (0); ) .... )
אזהרת PVS-Studio: V746 סוג חיתוך. חריג צריך להיתפס לפי הפניה ולא לפי ערך. object_item_script.cpp 39

פוּנקצִיָה std::exception::what()הוא וירטואלי וניתן להגדיר אותו מחדש במחלקות בירושה. בדוגמה זו, החריג נתפס לפי ערך, כך שמופע המחלקה יועתק וכל המידע על הסוג הפולימורפי יאבד. דבר אל מה()במקרה כזה זה חסר טעם. יש לתפוס את החריג באמצעות הפניה:
catch(const std::exception& e) (

שונות

void compute_cover_value (....) ( .... float value ; .... if (value< .999f) { value = value; } .... }
אזהרת PVS-Studio: V570 המשתנה "ערך" מוקצה לעצמו. compiler_cover.cpp 260

מִשְׁתַנֶה ערךמוקצה לעצמו. למה לעשות את זה לא ברור. אולי היה צריך לתת לזה משמעות אחרת.
void CActor::g_SetSprintAnimation(u32 mstate_rl, MotionID &head, MotionID &torso, MotionID &legs) ( SActorSprintState& sprint = m_anims->m_sprint; bool jump = (mstate_rl&mcFall) || (mstate_rl&rl&mcFall) || (mstate_rl)&rlanding_(mcstating_rl)&mstatat | _rl&mcL anding2) | | (mstate_rl&mcJump); .... )
אזהרת PVS-Studio: V501 ישנם תתי-ביטויים זהים "(mstate_rl & mcLanding)" משמאל ומימין ל-"||" מַפעִיל. actoranimation.cpp 290

סביר להניח שזו רק בדיקה נוספת. mstate_rl & mcLanding, אבל לעתים קרובות אזהרות כאלה מאותתות על שגיאה בלוגיקה וערכי ה-enum שלא נבדקו.

אזהרות דומות:

  • V501 ישנם תתי-ביטויים זהים "HudItemData()" משמאל ומימין לאופרטור "&&". huditem.cpp 338
  • V501 ישנם תתי-ביטויים זהים "list_idx == e_outfit" משמאל ומימין ל-"||" מַפעִיל. uimptradewnd_misc.cpp 392
  • V501 ישנם ביטויי משנה זהים "(D3DFMT_UNKNOWN == fTarget)" משמאל ומימין ל-"||" מַפעִיל. hw.cpp 312
RELATION_REGISTRY::RELATION_MAP_SPOTS::RELATION_MAP_SPOTS() ( .... spot_names = "enmy_location"; spot_names = "enmy_location"; .... )
אזהרת PVS-Studio: V519 למשתנה מוקצים ערכים פעמיים ברציפות. אולי זו טעות. קווי בדיקה: 57, 58. relation_registry.cpp 58

המנתח זיהה ששני ערכים מוקצים בשורה למשתנה אחד. במקרה זה, זה נראה כאילו זה רק קוד מת ויש להסירו.
void safe_verify(....) ( .... printf("שגיאה חמורה (%s): לא הצליח לאמת נתונים\n"); .... )
אזהרת PVS-Studio: V576 פורמט שגוי. צפוי מספר שונה של ארגומנטים בפועל בעת קריאה לפונקציה "printf". צפוי: 2. נוכח: 1. entry_point.cpp 41

בתפקוד printfלא עברו מספיק ארגומנטים: הפורמט "%s" מציין שיש להעביר מצביע למחרוזת. מצב זה יכול להוביל לשגיאת גישה לזיכרון ולסיום תוכנית חריג.

  • pvs-studio
  • ניתוח קוד סטטי
  • C++
  • העוקב
  • הוסף תגיות

    0) התקן את Visual Studio 2008 SP1 (מקצועי או צוות, בניתי אותו בראשון), ה-service pack מארכיון engine.vc2008.fixed.rar מתאים רק לגרסה האנגלית של הסטודיו, לרוסית אתה יהיה צורך להוריד אותו בנפרד.

    1) צור תיקיה בדיסק, יש בה תיקיה נוספת.

    2) בתיקייה זו אנו מניחים רק את התיקיה engine.vc2008 מהארכיון "engine.vc2008.fixed - הפרויקט vs2008 שתיקנתי", אנחנו לא נוגעים בתיקייה SDK משם.

    3) קח את תיקיית ה-SDK מהארכיון "stasvn\sources\engine.vc2005-2008(~1.6.02 benchmark) - מרץ 2010", מתיקיית המשנה מקורות.
    שמנו אותו בתיקייה אחת אל engine.vc2008

    4) כעת, נוסף על כך, אנו מדווחים על תיקיית SDK מארכיון engine.vc2008.fixed.rar, מסכימים להחליף את כל הקבצים

    5) הורד שני ערכות SDK של DirectX מאתר האינטרנט של מיקרוסופט - מרץ 2009 ויוני 2010. (המשקל של כל אחד הוא כ-500 מגה-גב), אתה יכול להשתמש רק בגרסת 2009, אבל אז לא תוכל לבנות את xrRender_R4. (קישור: שגיאה קטלנית LNK1181: לא יכול לפתוח את קובץ הקלט "d3d11.lib"), ואם אתה משתמש רק ב-2010, המשחק לא יתחיל עם R4.

    לאחר התקנת שני DX SDK, ודא שהם רשמו את הנתיבים שלהם לאולפן, קבצי SDK 2010 חייבים להיות לאחר 2009, כפי שמוצג באיור:

    הדבר נכון גם למקטעים של קבצי הפעלה ו-Include files. אם יש לך שאלות כלשהן, חפש בגוגל "חיבור directx sdk visual studio 2008"

    אם גרסאות ה-SDK שגויות (או שהיא לא מחוברת), היומן ישבע בהיעדר קבצים כמו d3dXX.lib \ .h)
    אין צורך להעביר תיקיות מ-DirectX SDK שכבר מותקן לשום מקום. מספיק להגדיר את הנתיבים אליהם באופן גלובלי עבור הסטודיו (או עבור כל פרויקט באופן ידני)

    הערה מ-loxotron: פשוט העתק ושנה את השם של d3d11_beta.lib ל-d3d11.lib בתיקייה עם ה-sdk הישיר, או אפילו טוב יותר, הורד והתקן את DX SDK אוגוסט 2009 ואל תתעסק עם גרסאות לא מתאימות.

    6) לכל מקרה, אתה יכול גם להתקין SDK \ OpenALwEAX.exe, אבל אני לא בטוח שזה נחוץ באופן קריטי.

    7) הפעל את הפרויקט דרך ..\CoP\Project\engine.vc2008\engine.sln. כאשר הוא נטען, בחלק העליון של האולפן, אנו משנים את מצב הבנייה מ-Debug_Dedicated (או כל אחר) ל-Release. לאחר מכן, בצד שמאל \ ימין תהיה רשימה של תיקיות עם קבצי מנוע, אנחנו צריכים, קודם כל, את התיקיה 3rd_party - לחץ לחיצה ימנית עליה ובחר Build \ Build.

    אם הכל תקין, אז בסוף היומן למטה יכתוב על 11 פרויקטים מוצלחים (או המספר יהיה קטן יותר אם כמה פרויקטים כבר נבנו בעבר, היומן ידווח גם על "דילוג \ מעודכן" על כך) 0
    אספתי לחלוטין את כל הפרויקטים ללא שגיאות. (אזהרות אינן נחשבות לשגיאות מן המניין)

    8) באנלוגיה, מלמעלה למטה, ניתן לבנות Dlls אחרים, אין צורך לבנות את התיקיות editor\dedicated\utils\plugins - הן לא חלות על המנוע. בניית xrGame.dll ייקח הכי הרבה זמן. השאר מהירים מספיק.

    אגב, אין צורך לאסוף את כל ה-DLL. אתה יכול רק צריך. כשהם מוכנים - צור תיקיית bin נקי בתיקיית המשחק. זרוק לשם את כל קבצי ה-dll שנוצרו (אתה יכול יחד עם .pdb). במידת הצורך, תוכל להעלות את הקבצים החסרים מה- RFP המקורי של bin (תיקון שני), אם המשחק דורש אותם. (כמו wrap_oal.dll)
    התחלתי את המשחק מה-Stalker-COP.exe המקורי

    אם הכל תקין, אז ביומן\קונסולה של המשחק, מבנה המשחק ותאריך הבנייה יצוינו בשורות הראשונות.

      תוֹכֶן
    • לאדה XRAY, יחד עם דגם Vesta, ניתן כעת לכנות התקווה והעמוד החדש של AvtoVAZ. המכוניות הללו הן שמייצגות את פני החברה וסבב חדש בפיתוחה. אין זה מפתיע שפיתוח ה-X-Ray האצ'בק החדש בוצע בזהירות רבה. יתר על כן, תשומת לב מיוחדת הוקדשה לא רק למראה, אלא גם למרכיב הטכני. והמנוע, כידוע, הוא "לב המכונית", ולכן המנועים תמיד היו בראש סדר העדיפויות של מהנדסי החברה.

      תיאור קצר של מנועי לאדה X Ray.

      רשימת מנועי לאדה X Ray

      בסך הכל, ההאצ'בק יקבל שלושה מנועים, וכמה יחידות מקומיות דוללו עם אחד "חו"ל". רשימת מנועים:

      מפרטים ומאפייני עיצוב

      כל יחידות הכוח של הדגם החדש מודרניות למדי ועומדות בכל הקריטריונים העדכניים החלים על פלח זה.

      VAZ-21129

      זהו מנוע בנזין ביתי שיוצר כבר זמן רב ומותקן גם בדגמי AvtoVAZ אחרים, כולל לאדה וסטה.

      • נפח - 1,596 ס"מ³;
      • תצורה - בשורה;
      • מיקום - רוחבי;
      • מספר צילינדרים - 4;
      • מספר שסתומים - 16;
      • הספק מרבי - 106 ליטר. עם. (78.2 קילוואט) ב-5,800 סל"ד;
      • מומנט מרבי - 148 ננומטר ב-4,200 סל"ד;
      • כונן תזמון - רצועה;
      • דינמיקה - 11.4 שניות;
      • מהירות מרבית - 176 קמ"ש;
      • יחס דחיסה - 11 יחידות;
      • קוטר צילינדר - 82 מ"מ;
      • מהלך בוכנה - 75.6 מ"מ;
      • תקנים סביבתיים - יורו-5;
      • דלק - AI-95;
      • צריכת דלק (עיר / כביש מהיר / מצב מעורב) - 9.3 ליטר / 7.2 ליטר / 5.9 ליטר.
      • פוטנציאל - 400+ HP. עם.
      • ללא אובדן משאב - 150 ליטר. עם.

      מנוע X Ray VAZ 21129.

      מנוע Lada X Ray VAZ-21129 נוצר על בסיס מנוע סדרת VAZ-21127, המיועד לדגם פריורה. בוצעו בו מספר שינויים ושיפורים. המשמעותיים ביותר הם השימוש בסט דשים בסעפת היניקה, שדרכם משתנה אורכו, מה שמבטיח פעולה במהירויות נמוכות וגבוהות במצב האופטימלי. בנוסף, בתכנון המנוע, המהנדסים נטשו את חיישן זרימת האוויר ההמונית. במקום זאת, סופקו שני מכשירים נוספים - אלו הם חיישני טמפרטורת אוויר וחיישני לחץ מוחלט. פתרון כזה מספק אפשרות לשליטה מלאה יותר על התערובת הדליקה, וגם מבטל את הסבירות של מהפכות "שחייה" במצב סרק.

      מאחורי הנפח הרגיל של 1.6 ליטר ו-16 שסתומים, ישנם ניואנסים רבים.

      גם בתכנון המנוע יושמו פתרונות חדשים בנושא המתלה של היחידה המותקנת על גבי תת-מסגרת ובוצעו שינויים במערכות הפליטה והיניקה. אמצעים אלו הבטיחו למנוע, בין היתר, ירידה ברעש הפעולה, כמו גם ירידה ברעילות ובצריכת הדלק.

      הסיפור הזה מפרט את מנוע VAZ 21129:

      HR16DE

      מנוע רנו-ניסאן H4M-HR16DE סופק על ידי שותפי AvtoVAZ מחברת אליאנס רנו ניסאן. הוא מיוצר במשך זמן רב והותקן בהצלחה בדגמים רבים אחרים של חברות צרפתיות ויפניות - אלה הם ניסאן טיידה, ניסאן וינגרוד, ניסאן נוט, לאדה וסטה, ניסאן קשקאי ואחרות.

      מנוע ה-X-Ray HR16DE במלוא הדרו.

      • נפח - 1,598 ס"מ³;
      • תצורה - בשורה;
      • מיקום - רוחבי;
      • מספר צילינדרים - 4;
      • מספר שסתומים - 16;
      • סוג כוח - הזרקת דלק מבוזרת עם בקרה אלקטרונית;
      • הספק מרבי - 110 ליטר. עם. (81 קילוואט) ב-5,500 סל"ד;
      • מומנט מרבי - 150 ננומטר ב-4,000 סל"ד;
      • כונן תזמון - שרשרת;
      • דינמיקה - 11.1 שניות;
      • מהירות מרבית - 181 קמ"ש;
      • יחס דחיסה - 10.7 יחידות;
      • קוטר צילינדר - 76 מ"מ;
      • מהלך בוכנה - 88 מ"מ;
      • תקנים סביבתיים - יורו-4/5;
      • דלק - AI-92/95;
      • צריכת דלק (עיר / כביש מהיר / מצב מעורב) - 8.9 ליטר / 6.8 ליטר / 5.6 ליטר.
      • פוטנציאל - 150+ HP. עם.
      • ללא אובדן משאב - 125 ליטר. עם.

      ליחידת הכוח הזו לאדה X Ray יש מספר תכונות. המאפיין ביותר הוא הפחתת ההספק - אם בדגמים אחרים הוא משתנה בין 114 ל-118 כ"ס. s., אז במקרה של X Ray זה הצטמצם ל-110 ליטר. עם., שנעשה על מנת להתאים את המנוע הזה למציאות של רוסיה ושאר מדינות חבר העמים.

      השימוש בשרשרת בהנעת תזמון הופכת אותה א-פריורית לאמינה יותר.

      לכן, במקום החגורה המוכרת לבעלי לאדה, משתמשים בשרשרת בעיצובה, מה שמגביר משמעותית את האמינות, מכיוון שהיא לא נשברת, והיא לא נמתחת בקרוב. אין היום מפצים הידראוליים אופנתיים - במקום אותם יש שסתומים מתכווננים רגילים. עם זאת, הליך כוונון הדוחף לא יידרש לפני 80,000 - 100,000 ק"מ. בין שאר המאפיינים, ניתן לייחד את השימוש בקומפלקס לשינוי תזמון השסתומים, קיבוע מחליף הפאזות ישירות על פיר היניקה, נוכחות של זוג חרירים בכל צילינדר, וגם שימוש במצערת מסוג אלקטרוני.

      הדחייה של מרימים הידראוליים הופכת לצורך להתאים את השסתומים.

      בנוסף, בתהליך המודרניזציה צומצמו מחווני החיכוך של רכיבי יחידת הכוח של Lada X Ray. זה הושג באמצעות שימוש בציפוי פלואור במוביל השרשרת, ליטוש (מראה), כמו גם עיבוד של גל הארכובה. במצב סרק צומצמו ההפסדים (דלק ושאיבה), דבר המובטח על ידי הגדלת זווית ההמרה C-VTC, וכן על ידי חישוב מחדש של הבקרה (זמנית).

      VAZ-21179

      זהו מנוע ביתי חדש, שפותח במיוחד עבור דגמי ה-X Ray ו-Vesta. יחידת הכוח של סדרת VAZ 21126 נבחרה כבסיס לה, שממנה הושאל בלוק הצילינדר. עם זאת, כאן מסתיים הדמיון ביניהם.

      החזק ביותר בשורה הוא מנוע VAZ-21179.

    1. נפח - 1,774 ס"מ³;
    2. תצורה - בשורה;
    3. מיקום - רוחבי;
    4. מספר צילינדרים - 4;
    5. מספר שסתומים - 16;
    6. סוג כוח - הזרקת דלק מבוזרת עם בקרה אלקטרונית;
    7. הספק מרבי - 122 ליטר. עם. (90 קילוואט) ב-6,050 סל"ד;
    8. מומנט מרבי - 170 ננומטר ב-3,750 סל"ד;
    9. כונן תזמון - רצועה;
    10. מספר גלי זיזים - 2 (סוג DOHC);
    11. דינמיקה - 10.9 שניות;
    12. מהירות מרבית - 186 קמ"ש;
    13. יחס דחיסה - 9.8 יחידות;
    14. מהלך בוכנה - 84 מ"מ;
    15. תקנים סביבתיים - יורו-5;
    16. דלק - AI-95;
    17. צריכת דלק (עיר / כביש מהיר / מצב מעורב) - 8.6 ליטר / 6.8 ליטר / 5.8 ליטר.
    • פוטנציאל - אין נתונים;
    • ללא אובדן משאב - ללא נתונים.

    מנוע ה-Lada X Ray הזה שונה בצורה מדהימה ממנועי VAZ אחרים. בתכנון יחידת הכוח נעשה שימוש בשסתום מצערת חדש, נטול הנעה מכנית, ראש הצילינדר צויד בשסתומים חדשים (קלי משקל) מבית Mahle, ולווסת הפאזה הובאו תעלות שמן נוספות.

    שסתום המצערת נטול הנעה מכנית.

    מהלך בוכנה גדול יותר הבטיח עלייה בנפח העבודה, גל הארכובה מאופיין ברדיוס ארכובה מוגדל, ותעלות היניקה של האספן מבית Ecoalliance (רוסיה) מוגדלות בקוטר ל-39 מ"מ. חיישן החמצן מסופק על ידי Bosch, ומשאבת החמצן מסופקת על ידי GMB (קוריאה). אותה חברה קוריאנית אחראית לאספקת משאבת הנפט בעלת הביצועים הגבוהים.

    גל ארכובה גדל ברדיוס הארכובה.

    קבוצת מוט חיבור ובוכנה (סוג קל משקל) מגיעה מהמותג Federal Mogul, וחברת INA הגרמנית מספקת מותחני רצועות שיניים אוטומטיים המצוידים בזוג גלילים. מסילת הדלק נרכשת מקונצרן קונטיננטל. החרירים שלו מתאפיינים בביצועים מוגברים, כתוצאה מכך התרסיס מותאם במיוחד לעבודת מנוע ה-X Ray החדש.

    גלי הזיזים עצמם מגיעים מקוריאה.

    כפי שניתן לראות, למרות פיתוח רוסי, חלק ניכר מהרכיבים נרכש מחברות זרות.

    הסרטון מציג את תהליך הרכבת מנוע 1.8 ליטר חדש עבור Lada X Ray: