Вконтакте Facebook Twitter Лента RSS

Игры с x ray на пк. Ошибка XRay Engine: описание и устранение

X-Ray был создан украинской компанией GSC GameWorld для игры S.T.A.L.K.E.R.: Тень Чернобыля. Движок включает рендер с поддержкой DirectX 8.1/9.0c/10/10.1/11, физический и звуковой движки, мультиплеер и систему искусственного интеллекта A-Life. Впоследствии компания создавала движок версии 2.0 для своей новой игры, но разработка была прекращена и исходные коды утекли в сеть.

Проект вместе со всеми его зависимостями легко собирается в Visual Studio 2015. Для проверки использовался исходный код движка версии 1.6 из репозитория на GitHub и статический анализатор кода PVS-Studio 6.04, загрузить который можно по ссылке .

Copy-paste

Для начала рассмотрим ошибки, связанные с копированием кода. Сценарий их возникновения в разных случаях обычно похож: скопировали код, поменяли часть переменных, а несколько - забыли. Такие ошибки могут быстро распространяться по кодовой базе, и без статического анализатора их очень легко пропустить.

MxMatrix& MxQuadric::homogeneous(MxMatrix& H) const { .... unsigned int i, j; for(i=0; iПредупреждение PVS-Studio : V533 It is likely that a wrong variable is being incremented inside the "for" operator. Consider reviewing "i". mxqmetric.cpp 76

Анализатор обнаружил, что во вложенном цикле for инкрементируется переменная i , а проверяется переменная j , что приводит к бесконечному циклу. Скорее всего, при копировании её просто забыли поменять.
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"), "%f,%f,%f", &data.m_attack_effector.ppi.color_base.r, &data.m_attack_effector.ppi.color_base.g, &data.m_attack_effector.ppi.color_base.b); if (ini->line_exist(ppi_section,"color_base")) sscanf(ini->r_string(ppi_section,"color_gray"), "%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 The conditional expressions of the "if" operators situated alongside each other are identical. Check lines: 445, 447. base_monster_startup.cpp 447
  • V581 The conditional expressions of the "if" operators situated alongside each other are identical. Check lines: 447, 449. base_monster_startup.cpp 449
В данном фрагменте используются подряд несколько одинаковых условных выражений. Очевидно, что необходимо заменить color_base на color_gray и color_add в соответствии с кодом в теле if ветви.
/* process a single statement */ 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 The use of "if (A) {...} else if (A) {...}" pattern was detected. There is a probability of logical error presence. Check lines: 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 It is odd that the body of "width" function is fully equivalent to the body of "height" function. tpixel.h 1090

Методы height() и width() имеют одинаковое тело. Учитывая, что вычисляются размеры граней куба, возможно, ошибки здесь нет. Но лучше переписать метод width() следующим образом:
size_t width() const { return cubeFaces.width(); }

Неправильное использование C++

C++ - замечательный язык, который предоставляет программисту много возможностей… отстрелить себе ногу особо жестоким образом. Неопределённое поведение, утечки памяти и, конечно же, опечатки - об ошибках такого рода пойдёт речь в текущем разделе.

Template struct _matrix33 { public: typedef _matrix33Self; 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 function should return a value. _matrix33.h 435

В конце метода пропущен return *this . По стандарту подобный код приведёт к неопределённому поведению. Так как возвращаемое значение является ссылкой, это, скорее всего, приведёт к падению программы при попытке обратиться к возвращаемому значению.
ETOOLS_API int __stdcall ogg_enc(....) { .... FILE *in, *out = NULL; .... input_format *format; .... in = fopen(in_fn, "rb"); if(in == NULL) return 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 The null pointer is passed into "fclose" function. Inspect the first argument. ogg_enc.cpp 47

Довольно интересный пример. Анализатор обнаружил, что аргумент в вызове fclose равен nullptr , что делает вызов функции бессмысленным. Можно предположить, что должны были закрыть поток in.
void NVI_Image::ABGR8_To_ARGB8() { // swaps RGB for all pixels assert(IsDataValid()); assert(GetBytesPerPixel() == 4); UINT hxw = GetNumPixels(); for (UINT i = 0; i < hxw; i++) { DWORD col; GetPixel_ARGB8(&col, i); DWORD a = (col >> 24) && 0x000000FF; DWORD b = (col >> 16) && 0x000000FF; DWORD g = (col >> 8) && 0x000000FF; DWORD r = (col >> 0) && 0x000000FF; col = (a << 24) | (r << 16) | (g << 8) | b; SetPixel_ARGB8(i, col); } }
Предупреждения PVS-Studio:

  • V560 A part of conditional expression is always true: 0x000000FF. nvi_image.cpp 170
  • V560 A part of conditional expression is always true: 0x000000FF. nvi_image.cpp 171
  • V560 A part of conditional expression is always true: 0x000000FF. nvi_image.cpp 172
  • V560 A part of conditional expression is always true: 0x000000FF. nvi_image.cpp 173
В данном участке кода перепутаны логические и битовые операции. Результат будет не таким, какого ожидал программист: col будет всегда равен 0x01010101 независимо от входных данных.

Правильный вариант:
DWORD a = (col >> 24) & 0x000000FF; DWORD b = (col >> 16) & 0x000000FF; DWORD g = (col >> 8) & 0x000000FF; DWORD r = (col >> 0) & 0x000000FF;
Ещё один пример странного кода:
VertexCache::VertexCache() { VertexCache(16); }
Предупреждение PVS-Studio : V603 The object was created but it is not being used. If you wish to call constructor, "this->VertexCache::VertexCache(....)" should be used. vertexcache.cpp 6

Вместо вызова одного конструктора из другого для инициализации экземпляра будет создан и тут же уничтожен новый объект типа VertexCache . В результате члены создаваемого объекта останутся непроинициализированными.
BOOL CActor::net_Spawn(CSE_Abstract* DC) { .... m_States.empty(); .... }
Предупреждение PVS-Studio : V530 The return value of function "empty" is required to be utilized. actor_network.cpp 657

Анализатор предупреждает, что возвращаемое функцией значение не используется. Похоже, что программист перепутал методы empty() и clear() : empty() не очищает массив, а проверяет, является ли он пустым.

Такие ошибки нередко встречаются в различных проектах. Проблема в том, что имя empty() не очевидно: некоторые воспринимают его как действие - удаление. Для того, чтобы подобной неоднозначности не возникало лучше добавлять глаголы has, is к началу метода: действительно, isEmpty() с clear() сложно перепутать.

Похожее предупреждение:

V530 The return value of function "unique" is required to be utilized. 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 The "memset" function processes "0" elements. Inspect the third argument. 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_result != WAIT_FAILED)) .... }
Предупреждение PVS-Studio : V547 Expression is always true. Probably the "&&" operator should be used here. 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); for (CInifile::SectCIt i=protections.Data.begin(); protections.Data.end() != i; ++i) { string256 buffer; BoneProtection BP; .... BP.BonePassBullet = (BOOL) (atoi(_GetItem(i->second.c_str(), 2, buffer))>0.5f); .... } }
Предупреждение PVS-Studio : V674 The "0.5f" literal of the "float" type is compared to a value of the "int" type. boneprotections.cpp 54

Анализатор обнаружил сравнение целочисленного значения с вещественной константой. Возможно, что здесь по аналогии должна была использоваться функция atof , а не 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* object, LPVOID params) { bullet_test_callback_data* pData = (bullet_test_callback_data*)params; SBullet* bullet = pData->pBullet; if((object->ID() == bullet->parent_id) && (bullet->fly_distflags.ricochet_was)) return FALSE; BOOL bRes = TRUE; if (object){ .... } return bRes; }
Предупреждение PVS-Studio : V595 The "object" pointer was utilized before it was verified against nullptr. Check lines: 42, 47. level_bullet_manager_firetrace.cpp 42

Проверка указателя object на равенство nullptr идёт после того, как разыменовали object->ID() . В случае, когда object равен 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 The "CoInitializeEx" function should not be called from "DllMain" function. xrcore.cpp 205

В теле DllMain нельзя использовать часть WinAPI функций, включая CoInitializeEx. Убедиться в этом можно, прочитав документацию на MSDN . Нельзя дать какой-то однозначный совет, как стоит переписать эту функцию, но стоит понимать, что такая ситуация опасна, так как она может привести к взаимной блокировке потоков или аварийному завершению.

Ошибки в приоритетах

int sgetI1(unsigned 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 Consider inspecting the statement of "*pointer++" pattern. Probably meant: "(*pointer)++". lwio.c 316

Ошибка связана с использованием инкремента. Для наглядности перепишем данное выражение, расставив скобки:
*(bp++);
То есть произойдёт сдвиг не содержимого по адресу bp, а самого указателя, что в данном контексте бессмысленно. Ниже по коду есть фрагменты вида *bp += N , из-за чего я и сделал вывод, что это ошибка.

Избежать подобной ошибки помогла бы расстановка скобок, что сделало бы порядок вычислений более понятным. Также неплохой методикой является использование const для аргументов, которые не должны меняться.

Аналогичные предупреждения:

  • V532 Consider inspecting the statement of "*pointer++" pattern. Probably meant: "(*pointer)++". lwio.c 354
  • V532 Consider inspecting the statement of "*pointer++" pattern. Probably meant: "(*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 It is possible that this "else" branch must apply to the previous "if" statement. hit_memory_manager.cpp 368

В этом фрагменте ветвь else относится ко второму if из-за своей право-ассоциативности, что не совпадает с форматированием кода. К счастью, данный случай не отражается на работе программы, тем не менее, он может усложнить процесс отладки и тестирования.

Рекомендация проста - в более-менее сложных ветвлениях расставляйте фигурные скобки.
void HUD_SOUND_ITEM::PlaySound(HUD_SOUND_ITEM& hud_snd, const Fvector& position, const IGameObject* parent, bool b_hud_mode, bool looped, u8 index) { .... hud_snd.m_activeSnd->snd.set_volume(hud_snd.m_activeSnd->volume * b_hud_mode?psHUDSoundVolume:1.0f); }
Предупреждение PVS-Studio : V502 Perhaps the "?:" operator works in a different way than it was expected. The "?:" operator has a lower priority than the "*" operator. 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)
Выражения, содержащие тернарный оператор, несколько if-else ветвей или операции И/ИЛИ, - это те случаи, когда лучше поставить лишние скобки.

Аналогичные предупреждения:

  • V502 Perhaps the "?:" operator works in a different way than it was expected. The "?:" operator has a lower priority than the "+" operator. uihudstateswnd.cpp 487
  • V502 Perhaps the "?:" operator works in a different way than it was expected. The "?:" operator has a lower priority than the "+" operator. uicellcustomitems.cpp 106

Лишние сравнения

void CDestroyablePhysicsObject::OnChangeVisual() { if (m_pPhysicsShell){ if(m_pPhysicsShell)m_pPhysicsShell->Deactivate(); .... } .... }
Предупреждение PVS-Studio : V571 Recurring check. The "if (m_pPhysicsShell)" condition was already verified in line 32. destroyablephysicsobject.cpp 33

В данном примере дважды проверяется m_pPhysicsShell . Скорее всего, вторая проверка лишняя.
void CSE_ALifeItemPDA::STATE_Read(NET_Packet &tNetPacket, u16 size) { .... if (m_wVersion > 89) if ((m_wVersion > 89)&&(m_wVersion < 98)) { .... }else{ .... } }
Предупреждение PVS-Studio : V571 Recurring check. The "m_wVersion > 89" condition was already verified in line 987. xrserver_objects_alife_items.cpp 989

Очень странный код. То ли здесь забыли выражение после if (m_wVersion > 89) , то ли целую серию else-if . Данный метод требует более подробного рассмотрения разработчиком проекта.
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 Consider inspecting the "(0 != txt) && ("#" == txt)" expression. The expression is excessive or contains a misprint. elog.cpp 29
  • V590 Consider inspecting the "(0 != txt) && ("!" == txt)" expression. The expression is excessive or contains a misprint. elog.cpp 31
В выражениях инициализации переменных bDlg и mt проверка (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 = 25.f; param_noise_scale = 1.f; im_noise_time = 1/100; im_noise_shift_w = 0; im_noise_shift_h = 0; .... }
Предупреждение PVS-Studio : V636 The "1 / 100" expression was implicitly cast from "int" type to "float" type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(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 The strconcat function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the first argument. space_restriction.cpp 201

Функция strconcat , в качестве первого параметра принимает длину буфера. Буфер S объявлен, как LPSTR , то есть как указатель на строку. sizeof(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 Be advised that compiler may delete this cycle or make it infinity. Use volatile variable(s) or synchronization primitives to avoid this. xrcdb.cpp 100

Компилятор может убрать проверку S_INIT == status в качестве оптимизации, так как переменная status не модифицируется в цикле. Для того, чтобы избежать подобного поведения, нужно использовать volatile переменные или типы синхронизации данных между потоками.

Аналогичные предупреждения:

  • V712 Be advised that compiler may delete this cycle or make it infinity. Use volatile variable(s) or synchronization primitives to avoid this. levelcompilerloggerwindow.cpp 23
  • V712 Be advised that compiler may delete this cycle or make it infinity. Use volatile variable(s) or synchronization primitives to avoid this. levelcompilerloggerwindow.cpp 232
void CAI_Rat::UpdateCL() { .... if (!Useful()) { inherited::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 Expression "squad->get_index(this) == u32(- 1)" is always false. The value range of unsigned char type: . ai_rat.cpp 480

Для того, чтобы понять, почему это выражение всегда ложно, вычислим значения отдельных операндов. u32(-1) равен 0xFFFFFFFF или 4294967295. Тип, возвращаемый методом squad->get_index(....) , - u8, следовательно его максимальное значение - 0xFF или 255, что строго меньше, чем u32(-1). Соответственно, значением такого сравнения всегда будет false . Данный код легко исправить, поменяв тип данных на u8:
squad->get_index(this) == u8(-1)
Та же диагностика срабатывает и для избыточных сравнений беззнаковых переменных:
namespace 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 Expression "m_tActionCondition.m_tLifeTime >= 0" is always true. Unsigned type value is always >= 0. script_entity_action_inline.h 115

Переменная m_tLifeTime является беззнаковой, соответственно она всегда больше или равна нулю. Является ли это лишней проверкой или же здесь скрыта ошибка в логике, судить разработчику.

Аналогичное предупреждение:

V547 Expression "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 section) const { ObjectFactory::ServerObjectBaseClass *object = nullptr; try { object = m_server_creator(section); } catch(std::exception e) { Msg("Exception [%s] raised while creating server object from " "section [%s]", e.what(),section); return (0); } .... }
Предупреждение PVS-Studio : V746 Type slicing. An exception should be caught by reference rather than by value. object_item_script.cpp 39

Функция std::exception::what() является виртуальной и может быть переопределена в наследуемых классах. В данном примере исключение ловится по значению, следовательно, экземпляр класса будет скопирован и вся информация о полиморфном типе будет потеряна. Обращаться к what() в таком случае бессмысленно. Исключение стоит перехватывать по ссылке:
catch(const std::exception& e) {

Разное

void compute_cover_value (....) { .... float value ; .... if (value < .999f) { value = value; } .... }
Предупреждение PVS-Studio : V570 The "value" variable is assigned to itself. compiler_cover.cpp 260

Переменная value присваивается сама себе. Зачем это делать - непонятно. Возможно, ей должно было быть присвоено другое значение.
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&mcLanding) || (mstate_rl&mcLanding) || (mstate_rl&mcLanding2) || (mstate_rl&mcJump); .... }
Предупреждение PVS-Studio : V501 There are identical sub-expressions "(mstate_rl & mcLanding)" to the left and to the right of the "||" operator. actoranimation.cpp 290

Вероятнее всего здесь просто лишняя проверка mstate_rl & mcLanding , но часто подобные предупреждения сигнализируют об ошибке в логике и нерассмотренных значениях enum.

Аналогичные предупреждения:

  • V501 There are identical sub-expressions "HudItemData()" to the left and to the right of the "&&" operator. huditem.cpp 338
  • V501 There are identical sub-expressions "list_idx == e_outfit" to the left and to the right of the "||" operator. uimptradewnd_misc.cpp 392
  • V501 There are identical sub-expressions "(D3DFMT_UNKNOWN == fTarget)" to the left and to the right of the "||" operator. hw.cpp 312
RELATION_REGISTRY::RELATION_MAP_SPOTS::RELATION_MAP_SPOTS() { .... spot_names = "enemy_location"; spot_names = "enemy_location"; .... }
Предупреждение PVS-Studio : V519 The variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 57, 58. relation_registry.cpp 58

Анализатор обнаружил, что одной переменной присваиваются подряд два значения. В данном случае похоже, что это просто мёртвый код и его стоит удалить.
void safe_verify(....) { .... printf("FATAL ERROR (%s): failed to verify data\n"); .... }
Предупреждение PVS-Studio : V576 Incorrect format. A different number of actual arguments is expected while calling "printf" function. Expected: 2. Present: 1. entry_point.cpp 41

В функцию printf передаётся недостаточное количество аргументов: формат "%s" указывает на то, что должен быть передан указатель на строку. Такая ситуация может привести к ошибке доступа к памяти и экстренному завершению программы. Добавить метки

X-Ray Engine – движок, который использовался в основных играх серии «СТАЛКЕР» и дополнений к ним. Был создан разработчиком игр GSC Game World. Включает в себя исходный код и инструменты для разработки (SDK).

Движок X-Ray Engine поддерживает DirectX с версии 9.0 по 11. Также в нем реализована технология отложенного освещения, благодаря которой реалистично отрисовывается эффект освещения. Также поддерживается смена времени суток, изменение погоды и мягкие тени. Физика в основана на другом движке Open Dynamics Engine. Он обеспечивает реалистичную механику столкновений и динамику движения твердых тел.

Помимо исходного кода, X-Ray Engine содержит инструментарий для разработки программного обеспечения (SDK). Он в первую очередь пригодится мододелам, которые хотели бы создать и добавить в игру собственные модификации.

Особенности движка

Применялся при создании игр серии «СТАЛКЕР».
Поддерживает DirectX версий с 9 по 11.
Поддерживает отложенное освещение, погодные явления, реалистичную механику столкновений.
Содержит инструменты для разработки собственных модификаций.

X-Ray Engine и инструментарий к нему свободно распространяется, поэтому движок можно скачать бесплатно.

X-Ray Engine - собственный игровой движок, созданный компанией GSC Game World для внутреннего пользования. Подавляющему большинству игроков данная компания известна как разработчик серии игр S.T.A.L.K.E.R. Именно на X-Ray и была создана оригинальная часть "Сталкера" - Тень Чернобыля, а также два официальных аддона: Чистое небо и Зов Припяти. Более того, модифицированную версию движка планировалось использовать для разработки многообещающего проекта S.T.A.L.K.E.R. 2. Который, к сожалению, был заморожен еще в 2011 году.

Назначение

В данный момент X-Ray Engine используется в основном создателями модов. Да, S.T.A.L.K.E.R - это серия игр к которой было выпущено огромное количество модификаций. В помощь моддерам компания GSC Game World выпустила инструментарий разработчика - SDK (Software Development Kit). Вот только "укомплектовать" его официальной документацией в GSC забыли, так что первым создателям модов приходилось работать с движком "на ощупь". Благо на момент написания данного обзора, в сети уже появилось огромное количество "мануалов" и даже тематических форумов, на которых люди обмениваются опытом работы с SDK.

Технические характеристики

Последняя версия X-Ray Engine поддерживает работу с DirectX 11. Кроме того, в движке реализована поддержка объемного освещения, сложных эффектов с большим количество частиц (вроде дыма). Кроме того, он обеспечивает довольно реалистичный рендеринг сложных сцен и работает с Ragdoll-физикой. Еще самая первая версия X-Ray Engine позволила разработчикам добавить в игру поддержку мягких теней, что на момент выпуска S.T.A.L.K.E.R Тень Чернобыля считалось настоящим техническим прорывом, особенно для игры с большими открытыми локациями.

Ключевые особенности

  • наличие официального SDK, который используется создателями модов;
  • поддержка DirectX 11;
  • обеспечение реалистичной физики и собственная система ИИ (A-Life);
  • реализация технологии рельефного текстурирования;
  • работа с мягкими тенями и объемным освещением;
  • поддержка до четырех миллионов полигонов в одном кадре;
  • отсутствие официальной документации от разработчика.

Игры на компьютере - прекрасный способ «убить время», развлечься да и просто отдохнуть. Даже не будучи завзятым геймером, человек зачастую имеет свои предпочтения в области геймдева. Кто-то любит шутеры, кто-то жить не может без стратегий.

В далеком 2006 году настоящим событием стал выход STALKER: Shadow of Chernobyl. Игра приобрела миллионы поклонников по всему миру. Последняя версия, Call of Pripyat, вышла в 2009 году, после чего количество фанатов игры резко возросло: атмосфера Чернобыльской АЭС настолько захватывает, что даже взрослые люди способны часами просиживать за ней.

К сожалению, многие пользователи жалуются на то, что ошибка XRay Engine не дает им получать никакого удовольствия от игры. С чем связано ее появление и как от нее избавиться? Именно этому и посвящена наша статья.

Что такое XRay?

Дабы узнать о способе решения проблемы, необходимо подробнее разобраться в ее первопричине. Начнем с того, что XRay - это игровой движок, который используется во всех частях «Сталкера».

Создан он был специально для этой игры, причем произошло это еще в далеком 2001 году. Так как сам проект STALKER оказался просто-таки былинным «долгостроем», свет он увидел только через пять лет. Сперва разработчики предполагали использовать его исключительно с DirectX 8, но уже к выходу первой части трилогии в него добавили поддержку DirectX 9. В 2008 году, когда был анонсирован выход многострадального «Чистого неба», туда же добавили 10-ю версию.

Наконец, «Зов Припяти» получил также DirectX 11. Впрочем, учитывая некоторые «шероховатости» в самом коде игры, полностью раскрыть весь потенциал 11-й версии движок оказался не в состоянии.

В чем выражается проявление ошибки?

Этот момент ни с чем не спутать. Игра внезапно останавливается, после чего происходит вылет на рабочий стол. Так как в диалоговом окне с описанием кода ошибки изображен большой жук, то XRay Engine на фанатских форумах нередко называют «зеленой бедой» и «жуком несчастья».

Впрочем, довольно лирики. С чем связано появление «жука»?

Причины появления

Увы, но однозначного ответа на столь животрепещущий вопрос попросту нет. Разработчики из GSC не особенно комментировали причины даже в тот период, когда компания еще существовала, а сейчас надеяться на подробные ответы и вовсе бессмысленно.

Методом «проб и ошибок» было выяснено, что чаще всего «летит» игра на компьютерах тех пользователей, у кого не установлены свежие драйвера на видеокарту. Так что если вы не знаете, какая конкретно версия этого ПО установлена на вашей машине, самое время заняться его обновлением.

Обновляем саму игру

Если вы были свидетелем появления «Чистого неба», то прекрасно помните все те «лестные» эпитеты, которыми игроки награждали разработчиков. И было за что! Играть и в самом деле было совершенно невозможно, причем ошибка XRay Engine была еще «цветочками»!

Чего стоят только бессмертные снайперы и полностью пустая «Темная долина»! Нормально играть получилось только с дополнением 1.5.04, причем все сохранения, которые были сделаны на предыдущих версиях, не работали. Словом, если у вас есть интернет, не поленитесь и зайдите на сайт разработчика. Все существующие патчи на все игры серии там есть, так что их нужно только скачать и установить. В этом случае XRay Engine ошибка в «Сталкере» наверняка будет появляться куда реже.

Пиратские версии

Так как разработчики не слишком учитывали интересы конечных пользователей, от нелегального копирования игру защищает небезызвестная система StarForce. Не приходится удивляться тому, что многие пользователи предпочитают скачивать NoDVD даже в тех случаях, когда у них на руках имеется лицензионный диск с игрой.

К сожалению, многие из этих «таблеток» как раз-таки вызывают появление ошибки XRay Engine. Что делать, если вы не хотите портить операционную систему StarForce, но и постоянно видеть «зеленого жука» также не горите желанием?

Увы, но выход один. Купите игру в Steam. Так как в этом магазине цифрового контента игра доступна также зарубежным пользователям (у которых StarForce запрещен в принципе), то от проблемы вы точно избавитесь.

Другие причины

Другим немаловажным фактором, который может способствовать возникновению ошибки, может быть ваше компьютерное железо. Слишком новые или старые комплектующие вполне могут и не ужиться с загадочным украинским движком, после чего вас постоянно будет преследовать XRay Engine ошибка. «Зов Припяти» на данный момент является самой «свежей» версией игры, у которой проблема с железом встречается реже всего. «Тень Чернобыля» и «Чистое небо» в этом отношении куда старее, а потому с новыми видеокартами они зачастую дружить отказываются напрочь.

Моды

Когда «Сталкер» только-только вышел, восторгам игроков не было предела. Игра и в самом деле давала ощущение едва ли не безграничной свободы. ГГ мог идти куда угодно, будучи практически неограниченным в направлении своего движения. Время шло, восторгов становилось все меньше.

Стало понятно, что вырезанные локации разработчики возвращать не собираются, да и экшена в игре маловато. Тогда-то и появились МОДы (модификации игры), порой вносившие в «Сталкера» действительно глобальные изменения.

Самым известным стал АМК-проект, без которого геймеры со стажем ныне проходить «Тень Чернобыля» и вовсе не советуют. Какие-то моды были очень удачными, какие-то не очень. Но практически во всех из них имеется XRay Engine ошибка. «Зов Припяти» этому явлению подвержен куда меньше по той причине, что модов на эту игру гораздо меньше.

Так что если вы используете МОД, то выход один - общаться с его разработчиком напрямую или же перелопачивать сотни страниц форумов, где игроки порой выкладывают неплохие самодельные «заплатки», которые в определенных условиях действительно способны устранять эту ошибку. Конечно же, надеяться на это можно далеко не всегда, так как в случае с XRay Engine («Зов Припяти» в особенности) что-то конкретное сказать сложно.

Читы

Иные игроки, которым кажутся излишне сложными некоторые уровни, нередко слишком увлекаются читами, при помощи которых можно соорудить для себя неограниченное количество оружия и снаряжения, получить в свое распоряжение лучшие артефакты.

Как водится, за все приходится расплачиваться. В данном конкретном случае это выражается в потере стабильности программы, когда XRay Engine ошибка в «Сталкере» начинает вылезать через каждые несколько секунд. Если так происходит, попробуйте попросту поискать другую версию чита. Благо, что сегодня в интернете их можно отыскать в тысячах экземпляров. Наконец, попробуйте пройти сложный уровень честно! Быть может, так вы получите куда больше удовольствия от игры.

«Шаманство»

Увы, но даже самые логичные и правильные, на первый взгляд, методы дают сбой, когда дело касается этого игрового движка. К примеру, если вы играете не с «родным» разрешением, это вполне может быть причиной появления данной ошибки.

Разрешение вашего монитора составляет 1280х1024, но играть вы предпочитаете на 800х600? Вполне вероятно, что в «Сталкер» XRay Engine появляется именно из-за этого. Поменяйте разрешение на нативное (рекомендованное для этого монитора). В ряде случаев столь немудреная мера помогает полностью устранить ошибку.

Иногда проблема проявляется в случае, когда у вас выставлен слишком маленький файл подкачки. В идеале его размер должен в два раза превышать объем оперативной памяти.

Как увеличить размер файла подкачки?

На самом деле сделать это совершенно несложно. Для этого щелкаете правой клавишей мыши по «Моему компьютеру», после чего в контекстном меню выбираете пункт «Свойства». В открывшемся диалоговом окне выбираете опцию «Дополнительные параметры системы». Щелкаете по кнопке «Параметры» в пункте «Быстродействие», после чего выбираете вкладку «Дополнительно». Затем нужно нажать «Изменить» в пункте «Виртуальная память», после чего ввести туда требуемое вам значение и кликнуть левой клавишей мыши по «ОК».

Изредка игру можно запустить, если в системе менее 512 Мб памяти, но делать этого не стоит: XRay Engine ошибка и жуткие «тормоза» все равно не дадут вам играть.

Наконец, нужно сказать об особенностях самой игры. Желательно отключить лишние пункты по улучшению изображения. Особенно справедливо это утверждение, если речь идет о «Сталкер Зов Припяти». XRay Engine очень часто появлялась в версии 1.6.0, когда игрок пытался выставить максимальные настройки качества.

И еще о драйверах. Не так уж и редко бывает, что ошибка досаждает тем пользователям, в компьютере которых имеется дискретная аудиокарта. Попробуйте обновить драйвера на нее, а в особо сложных случаях - отключите устройство из «Панели управления». Внимание! Делайте это аккуратно, так как в противном случае вы вообще можете лишиться всего звука на вашем компьютере.

Что же можно сказать в завершение всего нашего повествования? Желаем вам, чтобы никакие ошибки не мешали вам устанавливать новые игровые рекорды! Надеемся, что наши рекомендации вам помогут в этом деле.

Движок X-ray достаточно мало известен за пределами стран СНГ, да и у нас его знают немногие мододелы, и это не удивительно - на нем вышло всего 3 игры. А вот эти игры знает практически любой геймер - это трилогия S.T.A.L.K.E.R., одна из немногих качественных игровых серий, выпущенных на постсоветском пространстве. Она оказалась настолько захватывающей, что новые моды появляются даже сейчас, спустя 8 лет после выхода последней игры серии (Зов Припяти, 2009 год). А некоторые моды стали культовыми, радикально меняющими игру - они добавляли более умный ИИ, машины, больше оружия, новые сюжетные задания и даже локации. Увы - продолжение серии, игра S.T.A.L.K.E.R. 2, официально заморожена, но многие ждут ее так же, как и Half-Life 3.

История появления движка

Движок полностью разработала украинская игровая студия GSC Game World, над графической частью движка в основном работали программисты Алесь Шишковцов и Александр Максимчук (они же работали в 4A Games над проектом Metro 2033). Первая демонстрация движка была проведена в 2001 году:


Как видно, изначально тематики S.T.A.L.K.E.R. не было и близко - демонстрация была больше похожа на джунгли Far Cry 1. Однако уже тогда движок был достаточно продвинутым - работал на DirectX 7 (в дальнейшем к выходу Теней Чернобыля в 2007 году добавили поддержку DirectX 8 и 9), поддерживал Detail mapping, 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 (Transform and Lighting - механизм, преобразующий 3D объект из одного опорного кадра в другой);
  • Технология отложенного освещения и затенения, которая позволяет достичь высокой достоверности в рендеринге освещения при высокой геометрической сложности сцены;
  • Продвинутая Level of Detail технология для всей геометрии;
  • Высокодетализированные персонажи и оружие;
  • Высокоскоростная смешанная система анимации, способная на неограниченное число интерполяции костей и модульных операций;
  • Поддержка SSE/3Dnow! технологий для процессоров Intel и AMD соответственно, позволяющие оптимизировать нагрузку на них;
  • Основанная на портальной системе, нелинейная система определения видимости;
  • Технологии Dynamic occlusion/contribution culling (отключение рендеринга объектов, находящихся за пределами камеры или на большом расстоянии);
  • Адаптирующаяся под «железо» технология кешированния;
  • Колорированное динамическое освещение и динамические «мягкие» тени;
  • Разрушаемые анимированные источники света;
  • Продвинутый выбор источника света, совмещение и его разделение, отбрасывание теней персонажами;
  • Система частиц с реальной физикой;
  • Продвинутая шейдерная система;
  • Динамическая смена погоды, дня и ночи.
X-Ray Engine 1.0

В единственной игре на этом движке, Тени Чернобыля, изначально на выбор в настройках было два API - DirectX 8 с особенностями, описанными выше, и DirectX 9, добавляющий еще несколько графических эффектов:
  • Рендеринг в высоком динамическом диапазоне (HDR) с плавающей запятой;
  • Bump mapping, Normal mapping и Parallax mapping (различные виды рельефного текстурирования);
  • Полностью динамическое освещение, мягкие тени;
  • Depth of field (глубина резкости), Motion Blur (размытие в движении), Bloom (размытие света на краях объекта) и динамические лучи света.
Игра, хоть и была долгостроем, получилась хорошей по графике, в основном за счет фотореалистичных объектов зоны (разработчики ездили в ЧЗО несколько раз для фотографирования):




A-Life

Еще одна особенность движка, которой могут гордиться разработчики - это система искусственного интеллекта A-Life (artificial life - искусственная жизнь). Сами разработчики описывают ее так:

Суть заключается в том, что персонажи в игре живут своей жизнью и существуют всё время, а не только когда их видит игрок. [...] Мы ввели два термина, характеризующие 2 модели поведения персонажа, отличающихся степенью детализации: офлайн и онлайн. Офлайновое поведение персонажа является очень простым с точки зрения детализации: персонаж не отыгрывает анимации, звуки, не управляет активно инвентарём, не строит детализированные сглаженные пути (хотя строит пути по глобальному навигационному графу, но об этом позже) и т.д. Онлайновое поведение напротив имеет полную степень детализации. Т.е. можно считать, что офлайновое поведение является плодом онлайнового.

В нашей системе пока игрок играет на своём уровне, другие персонажи живут на других уровнях, т.е. находятся в офлайне, т.е. используют офлайновое поведение. Более того, ввиду большой населённости, не все персонажи в пределах одного уровня имеют онлайновое поведение, а лишь те, кто находится в заданном радиусе от игрока (это может зависеть от уровней, обычно в районе 150 метров) или же по желанию геймдизайнеров.

Для реализации этого симулятор следит за передвижением игрока и объектов в офлайне и переводит их в онлайн/офлайн. При вычислении перехода объектов используется стандартный трюк с инерцией: радиус перехода в офлайн больше радиуса перехода в онлайн.

Далее стоит сказать о навигации объектов в онлайне и офлайне. У нас в игре есть уровни, для каждого из которых создаётся свой навигационный граф, который используют персонажи для передвижения в онлайне. Мы называем его детальным графом. Для каждого детального графа также создаётся его менее детализированный аналог, вершины которого можно связать с вершинами такого же графа другого уровня/ей. Т.е. после объединения всех таких графов воедино мы получаем граф, который объединяет все уровни. Он и используется персонажами для передвижения в офлайне. Также им пользуются персонажи в онлайне, когда они выполняют свои стратегические цели. Например, если персонаж в онлайне решил идти на другой уровень, то он строит путь по глобальному графу, затем строит путь по детальному графу своего уровня со своей позиции до точки глобального графа. Если эта точка уже на другом уровне, то он телепортируется туда и автоматически переходит в офлайн. Для того, чтобы это не происходило на глазах у игрока, мы точки перехода для игровых персонажей ставили дальше точки перехода игрока, где-то «за углом»

Как видно, ИИ сделан очень качественно, и на протяжении всей игры нет ощущения, что Зона мертва - постоянно происходят какие-то события: перестрелки, встреча различных сталкеров, мутантов, появление новых сообщений на КПК и т.д.

X-Ray Engine 1.5

Через год послы выхода Теней Чернобыля, в 2008 году, вышла новая часть игры, Чистое Небо. В игру добавили новое оружие и локации, а так же поддержку нового API - DirectX 10. Это позволило существенно улучшить качество воды и частиц, а так же добавить поддержку намокающих поверхностей (то есть поверхность до и после дождя выглядит по-разному) и Steep Parallax Mapping (реалистичное отображение выпуклых объектов на плоской текстуре - например, выпирающих камней в стене). Но в общем и целом графика была на уровне предыдущей части игры:


X-Ray Engine 1.6

В заключительной части трилогии, Зов Припяти, вышедшей в 2009 году, движок получил поддержку DirectX 11. Однако увы - все его особенности движок 8илетней давности не потянул, поэтому добавили только тесселяцию (процесс добавления новых выпуклых многоугольников в полигональную сетку с целью повышения детализации сетки, иными словами - выпуклые объекты стали реалистичнее). Общий уровень графики остался тем же:


Физический движок

В «X-Ray» используется свободный физический движок Open Dynamics Engine (ODE). Его особенности:

  • Высокая скорость обработки столкновений (быстрее, чем в коммерческих движках MathEngine, Havok, и т.д.), обнаружение столкновений оптимизировано для большого числа запросов в высокополигональной среде;
  • Реалистичная симуляция баллистики, движения, физики машин и т.д.
X-Ray Engine 2

Игра S.T.A.L.K.E.R. 2 на движке X-Ray 2 была анонсирована в августе 2010 года, выход игры предполагался в 2012. Однако в декабре 2011 года разработка игры была остановлена, и до сих пор не продолжена, хотя игровая студия GSC, разрабатывающая игру, существует и сейчас - в сентябре 2016 года она выпустила игру Казаки 3. Известно, что на момент заморозки проекта движок был готов на 70-80%, а так же было сделано несколько игровых уровней и персонажей. В игре предполагался бесшовный мир, а физическим движком выступал Havok. С учетом давности разработки S.T.A.L.K.E.R. 2 скорее всего уже не выйдет никогда, превращаясь в «вечный» проект типа Half-Life 3.
Партнеры
© 2020 Женские секреты. Отношения, красота, дети, мода