| 
				
				Подвисает сервер
				 |   |  
| 
GreenBytes
 | 
Дата: Воскресенье, 22.11.2020, 17:04:11 | Сообщение # 1 |  
  
  |  
Сообщений: 19
 
Репутация: 0 [ +/- ]
 |   
 | 
Добрый вечер. Я пишу плагины для сервера, но столкнулся с проблемой что сервер спустя некоторое время начинает подглючивать. Опыт программировании у меня имеется на множество ЯП, а так-же в веб программировании . Это я к тому что понимаю что пишу в плагине.
  Плагин прикрепить я не могу, он состоит из составных частей для удобства к прочтению ну и является полноценным оригиналом.
  Начну. Умирающая игра: Half-Life 2 DM, Sourcemod.
 
 Код meta list Listing 3 plugins:   [01] SourceMod (1.10.0.6478) by AlliedModders LLC   [02] SDK Tools (1.10.0.6478) by AlliedModders LLC   [03] SDK Hooks (1.10.0.6478) by AlliedModders LLC 
  Дело в том что после несколько часов пребывания на сервере он начинает подглючивать. При этом пинг стабильный, глюки сервера сопровождаются "откидыванием назад" и высвечивающим "WARNING..."
  В плагине используется база данных, но как показала практика что глючит не из -за базы данных. Почему я решил что глючить начинает из -за плагина ? Отвечаю. Потому что когда я его подключаю подлаивает сервер спустя время.
  Есть способ определить из -за чего происходят подобное ? Возможно с кем -то можно связаться для консультации по этому вопросу !?
  Команда sm_dump_handles handles.txt показала по моему плагину такой результат:
 Код 0x02cf0097    fish.smx             Timer                -1         0x34b9009d    fish.smx             KeyValues            6156       0x02d100a0    fish.smx             IDatabase            -1     0x02cd006d    fish.smx             CellArray            148        0x02ce006e    fish.smx             HudSyncObj           64      
  Почему около Timer и IDatabase пишет -1 ?
  Отрывок использования баз данных:
 Код //------------------------------------------------------------------------------------------------------- //  function: LoadPlayer //   Description: Загрузка данных с сервера о игроке //------------------------------------------------------------------------------------------------------- public void LoadPlayer(int client) {     char szQuery[512], szAuth[32];     GetClientAuthId(client, AuthId_Engine, szAuth, sizeof(szAuth), true);     FormatEx(szQuery, sizeof(szQuery), "SELECT * FROM `db_user` WHERE `steam` = '%s';", szAuth);     hDatabase.Query(LoadPlayer_DB, szQuery, GetClientUserId(client)); }
  //------------------------------------------------------------------------------------------------------- //  function: LoadPlayer_DB //   Description: Подключение к базе данных //------------------------------------------------------------------------------------------------------- public void LoadPlayer_DB(Database hDatabase, DBResultSet hQuery, const char[] sError, any iUserID) {     int iClient = GetClientOfUserId(iUserID);     if(sError[0]) {   LogError("LoadPlayer_DB: %s", sError);   return;     }     if (iClient) {   // Игрок живой   if (hQuery.RowCount != 0) {    // Игрок имеется в базе данных    hQuery.FetchRow();    HookPlayerLoad(iClient, hQuery);    LoadFishingPlayer(iClient);    LoadPrefixPlayer(iClient);    LoadSkinPlayer(iClient);   }else{    // Игрока нету в базе данных    CreatePlayer(iClient);   }     }     return; }
  
  Ничего ли я тут не упустил с закрытием handle ?
  Тут я привожу полный свой модуль где используется CreateKeyValues, возможно об этом упоминалось тут:
 Код 0x34b9009d    fish.smx             KeyValues            6156      0x02cd006d    fish.smx             CellArray            148        
  Ничего ли я тут не упустил с закрытием handle и прочих утечек памяти?
 Код //------------------------------------------------------------------------------------------------------- //  function: HookMap //   Description: Создание карты //------------------------------------------------------------------------------------------------------- public void HookMap() {     g_mapArray = CreateArray(); }
  //------------------------------------------------------------------------------------------------------- //  function: CreateMap //   Description: Создание карты //------------------------------------------------------------------------------------------------------- public void CreateMap() {     CreateTimer(4.0, TimeCreateMap, _); }
  //------------------------------------------------------------------------------------------------------- //  function: DeleteMap //   Description: Удаление карты //------------------------------------------------------------------------------------------------------- public void DeleteMap() {     int count = GetArraySize(g_mapArray);     for (int i=0; i<count; i++) {   if (IsValidEntity(GetArrayCell(g_mapArray, i, 0, false))) {    AcceptEntityInput(GetArrayCell(g_mapArray, i, 0, false), "kill");   }     }     ClearArray(g_mapArray); }
  //------------------------------------------------------------------------------------------------------- //  function: TimeCreateMap //   Description: Создание карты //------------------------------------------------------------------------------------------------------- public Action:TimeCreateMap(Handle:timer) {     char szName[128], szType[128], szModel[128], szTexture[128], szTargetName[128], szWeapon[128], szHook[128], szRelationship[128], szSolid[128], szScale[128];     float Location[3], Angle[3], Vector[3];     int izEntity, izHealth, izParent, izTime, izMode;     char szMap[128], szFile[128];     int iEntity, iEntity2;     ClearArray(g_mapArray);     GetCurrentMap(szMap, sizeof(szMap));     Format(szFile, sizeof(szFile), "cfg/map/%s.json", szMap);     Handle hKey = CreateKeyValues("fishing");     PrintToServer("Open file: %s", szFile);     if (!FileToKeyValues(hKey, szFile)) { PrintToServer("Not file: %s", szFile); CloseHandle(hKey); return Plugin_Stop; }     if (!KvJumpToKey(hKey, "obj 1", false)) { PrintToServer("Not read - obj 1"); CloseHandle(hKey); return Plugin_Stop; }     do {         iEntity = 0;         KvGetSectionName(hKey, szName, sizeof(szName));         KvGetString(hKey, "type", szType, sizeof(szType) );         KvGetString(hKey, "model", szModel, sizeof(szModel) );         KvGetString(hKey, "texture", szTexture, sizeof(szTexture) );         KvGetString(hKey, "targetname", szTargetName, sizeof(szTargetName) );         KvGetString(hKey, "weapon", szWeapon, sizeof(szWeapon) );         KvGetString(hKey, "hook", szHook, sizeof(szHook) );         KvGetString(hKey, "relationship", szRelationship, sizeof(szRelationship) );         KvGetString(hKey, "solid", szSolid, sizeof(szSolid) );         KvGetString(hKey, "scale", szScale, sizeof(szScale) );         KvGetVector(hKey, "pos", Location);         KvGetVector(hKey, "ang", Angle);         KvGetVector(hKey, "vector", Vector);         izEntity = KvGetNum(hKey, "entity", 0);         izHealth = KvGetNum(hKey, "health", 100);   izParent = KvGetNum(hKey, "parent", 0);         izTime   = KvGetNum(hKey, "time", 60);         izMode   = KvGetNum(hKey, "mode", 0);         // ----------------------------------------------------------------------------------------------         // Description: Создание объекта         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "prop_dynamic")) {             iEntity = CreatePropDynamic(Location, Angle, szModel, szSolid);    PushArrayCell(g_mapArray, iEntity);         }         // ----------------------------------------------------------------------------------------------         // Description: Создание и вывод спрайта         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "env_sprite")) {             iEntity = CreateSprite(Location, szTexture, szScale);    PushArrayCell(g_mapArray, iEntity);         }         // ----------------------------------------------------------------------------------------------         // Description: Удаление объекта по его ID         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "kill")) {             AcceptEntityInput(izEntity, "kill");         }         // ----------------------------------------------------------------------------------------------         // Description: Отрытие и закрытие дверей по ID         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "lock")) {             AcceptEntityInput(izEntity, "lock");         }         if(StrEqual(szType, "unlock")) {             AcceptEntityInput(izEntity, "unlock");         }         // ----------------------------------------------------------------------------------------------         // Description: Создание NPC         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "npc")) {    iEntity = CreateNPC(Location, izHealth, szModel, szWeapon);    PushArrayCell(g_mapArray, iEntity);    SetRelationship(iEntity, szRelationship);             SetTargetName(iEntity, szTargetName);    if (izParent == 1) {                 Location[0] += Vector[0];                 Location[1] += Vector[1];                 Location[2] += Vector[2];     iEntity2 = CreateSprite(Location, szTexture, szScale);     PushArrayCell(g_mapArray, iEntity2);                 SetParent(iEntity2, szTargetName);    }             if (StrEqual(szHook, "use")) {                 SDKHook(iEntity, SDKHook_Use, OnMapHookUse);             }   }         // ----------------------------------------------------------------------------------------------         // Description: Установка позиции тюрьмы         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "prison")) {    vecPrison[0] = Location[0];    vecPrison[1] = Location[1];    vecPrison[2] = Location[2];    PrintToChatAll("\x08FFFFFFFF[!] Координаты тюрьмы изменились");         for (int i=1; i<=MaxClients; i++) {     if ( IsClientInGame(i) ) {      if (PlayerStructure[i][PlayerPrison] == 1) {       TeleportEntity(i, vecPrison, NULL_VECTOR, NULL_VECTOR);      }     }    }   }         // ----------------------------------------------------------------------------------------------         // Description: Установка лимита карты         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "timeleft")) {             ServerCommand("mp_timelimit %d", izTime);         }     } while (KvGotoNextKey(hKey));     CloseHandle(hKey);     return Plugin_Stop; }
  public Handle GetKeyMap(int entity) {     char szMap[128], szFile[128], szTargetName[128], szName[128];     GetEntPropString(entity, Prop_Data, "m_iName", szName, sizeof(szName));     GetCurrentMap(szMap, sizeof(szMap));     Format(szFile, sizeof(szFile), "cfg/map/%s.json", szMap);     Handle hKey = CreateKeyValues("fishing");     PrintToServer("Open file: %s", szFile);     if (!FileToKeyValues(hKey, szFile)) { PrintToServer("Not file: %s", szFile); CloseHandle(hKey); return 0; }     if (!KvJumpToKey(hKey, "obj 1", false)) { PrintToServer("Not read - obj 1"); CloseHandle(hKey); return 0; }     do {         KvGetString(hKey, "targetname", szTargetName, sizeof(szTargetName) );         if (StrEqual(szTargetName, szName)) {             return hKey;         }     } while (KvGotoNextKey(hKey));     CloseHandle(hKey);     return 0; }
  public Action OnMapHookUse(int entity, int activator, int caller, UseType type, float value) {     char szName[64];     char szUse[128];     float Vector[3];     Handle hKey = GetKeyMap(entity);     if (hKey == 0) return Plugin_Continue;     if (PlayerStructure[activator][FishingFlag:PlayerPrison] == 1) return Plugin_Continue;     GetClientName(activator, szName, sizeof(szName));     KvGetString(hKey, "use", szUse, sizeof(szUse) );     KvGetVector(hKey, "teleport", Vector);     if (StrEqual(szUse, "teleport")) {         TeleportEntity(activator, Vector, NULL_VECTOR, NULL_VECTOR);     }     if (StrEqual(szUse, "shop")) {   ConsoleShop(activator, 0);     }     CloseHandle(hKey);     PlayerStructure[activator][FishingFrag:PlayerFishEntity] = 0;     return Plugin_Continue; } 
  По факту последний код парсит из файла cfg/map/%s.json , где %s имя карты. Объекты создаваемые на карте, на счет объектов ничего криминального нету, только те что имеются в игре. За исключением файлов спрайтов:
 Код // ----------------------------------------------------------------------------------------------         // Description: Создание и вывод спрайта         // ----------------------------------------------------------------------------------------------         if(StrEqual(szType, "env_sprite")) {             iEntity = CreateSprite(Location, szTexture, szScale);    PushArrayCell(g_mapArray, iEntity);         } 
  Где функция CreateSprite()
 Код //------------------------------------------------------------------------------------------------------- //  function: CreateSprite //   Location[3] - Вектор позиции //          szModel     - Путь к файлу модели //          szScale     - Размер спрайта //------------------------------------------------------------------------------------------------------- public int CreateSprite(float Location[3], char[] szModel, char[] szScale) {     int iEntity = CreateEntityByName("env_sprite"); //     if (iEntity <= MaxClients) return 0;     DispatchKeyValue(iEntity, "model", szModel);     DispatchKeyValue(iEntity, "spawnflags", "1");     DispatchKeyValue(iEntity, "rendermode", "1");     DispatchKeyValue(iEntity, "scale", szScale);     DispatchSpawn(iEntity);     TeleportEntity(iEntity, Location, NULL_VECTOR, NULL_VECTOR);     return iEntity; } 
  Картинки в формате *.vtf, *wmt грузятся на сервер с помощью fastDL ( веб сервер ) Я прикрепил картинки с демонстрации того что выполняет выше код....
 
  
  
  Надеюсь на вашу поддержку. Спасибо!Добавлено (22.11.2020, 17:43:35) --------------------------------------------- После написания поста обновил SourceMod, откомпилировал плагин...
  Код  meta list   [01] SourceMod (1.10.0.6499) by AlliedModders LLC   [02] SDK Tools (1.10.0.6499) by AlliedModders LLC   [03] SDK Hooks (1.10.0.6499) by AlliedModders LLC  
 
| 
Гости не могут скачивать файлы
 |   
 | 
 
|   | 
 |    |  
| 
_wS_
 | 
Дата: Воскресенье, 22.11.2020, 18:33:04 | Сообщение # 2 |  
  
 | 
Первое что приходит в голову, это как используется SQL. Есть запросы, которые выполняются сразу (SQL_Query), и которые выполняются в отдельном потоке (SQL_TQuery), никак не мешая серверу. Если запрос требует немедленный ответ (как SQL_Query) и сайт подвис или еще что-то не то с mysql, то сервер зависает и ждет несколько лет ответ. Поэтому для начала попробуй перевести всю связь с mysql в отдельный поток. Если используется sqlite, то мне кажется лучше перейти на mysql, чтобы все вычисления/запись обрабатывались на другой машине.
 
 Цитата GreenBytes (  )   Почему около Timer и IDatabase пишет -1 ?  Это нормально.
 
 Код public void HookMap() {     g_mapArray = CreateArray(); }  Я бы наверно сделал:
 
 Код public void HookMap() {     if (g_mapArray == INVALID_HANDLE) {         g_mapArray = CreateArray();     }     else {         ClearArray(g_mapArray);     } } 
  Еще ты хранишь индексы entity, мне кажется это не совсем надежно, пример проблемы: предмет A создан - его индекс 1021 предмет A удален предмет B создан - его индекс может быть 1021 (занимает свободный индекс) Поэтому надежнее хранить Ref:
 
 Код new ref = EntIndexToEntRef(1021); // этот ref и сохраняем new index = EntRefToEntIndex(ref); if (index > MaxClients) {     // Это точно наша entity (живая) }  
 | 
 
|   | 
 |    |  
| 
GreenBytes
 | 
Дата: Воскресенье, 22.11.2020, 19:29:29 | Сообщение # 3 |  
  
  |  
Сообщений: 19
 
Репутация: 0 [ +/- ]
 |   
 | 
Для MySQL у меня используется отдельная машина и на ней -же установлен сайт, сайт не подвисает когда сервер начинает подглючивает. Я думаю подлагивания SQL можно исключить, писал отдельно плагин с работой только SQL не каких зависаний не было замечено.
  SQL реализован по такому принципу, надеюсь все верно делаю.
 Код //------------------------------------------------------------------------------------------------------- //  function: HookDataBase //   Description: Подключение к базе данных //------------------------------------------------------------------------------------------------------- public void HookDataBase() {     Database.Connect(ConnectCallBack_DB, "fishing"); }
  //------------------------------------------------------------------------------------------------------- //  function: ConnectCallBack_DB //   Description: Подключение к базе данных //------------------------------------------------------------------------------------------------------- public void ConnectCallBack_DB(Database hDB, const char[] sError, any data) {     if (hDB == INVALID_HANDLE) {   PrintToChatAll("\x08FFFFFFFF[!] Плагин отключен, нет соединения с БД.");   LogError("ConnectCallBack_DB: %s", sError);   return;     }          hDB.SetCharset("utf8");          hDatabase = hDB;          UpdateLoadPlayer();     PrecacheSkin();     return; }
  //------------------------------------------------------------------------------------------------------- //  function: LoadPlayer //   Description: Загрузка данных с сервера о игроке //------------------------------------------------------------------------------------------------------- public void LoadPlayer(int client) {     char szQuery[512], szAuth[32];     GetClientAuthId(client, AuthId_Engine, szAuth, sizeof(szAuth), true);     FormatEx(szQuery, sizeof(szQuery), "SELECT * FROM `db_user` WHERE `steam` = '%s';", szAuth);     hDatabase.Query(LoadPlayer_DB, szQuery, GetClientUserId(client)); }
  //------------------------------------------------------------------------------------------------------- //  function: LoadPlayer_DB //   Description: Подключение к базе данных //------------------------------------------------------------------------------------------------------- public void LoadPlayer_DB(Database hDatabase, DBResultSet hQuery, const char[] sError, any iUserID) {     int iClient = GetClientOfUserId(iUserID);     if(sError[0]) {   LogError("LoadPlayer_DB: %s", sError);   return;     }     if (iClient) {   // Игрок живой   if (hQuery.RowCount != 0) {    // Игрок имеется в базе данных    hQuery.FetchRow();    HookPlayerLoad(iClient, hQuery);    LoadFishingPlayer(iClient);    LoadPrefixPlayer(iClient);    LoadSkinPlayer(iClient);   }else{    // Игрока нету в базе данных    CreatePlayer(iClient);   }     }     return; }
   Все запросы выполняются подобным образом как выполнена функция: LoadPlayer();
  На счет HookMap() функция выполняется 1 раз при старте плагина
 Код Handle g_mapArray;
  public void HookMap() {     g_mapArray = CreateArray(); }
  //------------------------------------------------------------------------------------------------------- //  function: OnPluginStart //   Description: Включение плагина //------------------------------------------------------------------------------------------------------- public OnPluginStart() {     HookDataBase();     HookEventPlayer();     HookFishing();     HookEventSay();     HookEventCmd();     HookEventNPC();     HookMap();          g_hHUD = CreateHudSynchronizer();          CreateTimer(1.0, OnTimerCallBack, _, TIMER_REPEAT); } 
 
 Цитата  предмет A создан - его индекс 1021 предмет A удален предмет B создан - его индекс может быть 1021 (занимает свободный индекс) 
  В принципе только не стандартными методами можно удалить объекты созданные той функцией, но я все -же для большей надежности переделаю под функции: EntIndexToEntRef, EntRefToEntIndex;
  Все ли в порядке с SQL работой ? Какие методы отладки проблемного участка кода можно применить ? 
 
 Сообщение отредактировал GreenBytes - Воскресенье, 22.11.2020, 19:30:46  | 
 
|   | 
 |    |  
| 
_wS_
 | 
Дата: Воскресенье, 22.11.2020, 19:41:28 | Сообщение # 4 |  
  
 | 
Попробуй profiler (позволяет узнать сколько секунд выполнялся код).
 
 Код new Handle:prof; public OnPluginStart() { prof = CreateProfiler(); }
  // И теперь в функциях/событиях пишешь
  StartProfiling(prof); // в самом верху
  // тут посередине какой-то код
  StopProfiling(prof); // в самом низу LogToFileEx("addons/sourcemod/logs/x.log", "MyFunc1 time = %f", GetProfilerTime(prof));  По идее поможет найти подвисший код. 
 | 
 
|   | 
 |    |  
| 
GreenBytes
 | 
Дата: Воскресенье, 22.11.2020, 20:07:16 | Сообщение # 5 |  
  
  |  
Сообщений: 19
 
Репутация: 0 [ +/- ]
 |   
 | 
Я боюсь что подлагивания вызвано движком самой игры ( сервера ), а не кодом плагина. Единственное что кажется код плагина как -то этому сопутствует, к примеру создаются какие -то Entity после чего происходят лаги.
  К примеру один глюк я разгадал. Я делал прекеш моделек ( скинов ), далее использовал setModel ( вроде так называется функция ), и спустя несколько смен карт были просто дикие лаги. ( утечка памяти )Добавлено (23.11.2020, 06:37:20) --------------------------------------------- Расставил несколько функций CreateProfiler(); StartProfiling(); StopProfiling();
  По таймауту было все хорошо. Время выполнения кода было примерно одинаково.
  Решил сделать так, как только сервер начал глючить я выгрузил плагин с сервера. Сервер продолжил глючить. Т.е проблема скорее всего не в выполнения кода, а что-то либо с утечкой памяти или с Entity...  
 | 
 
|   | 
 |    |  
| 
_wS_
 | 
Дата: Понедельник, 23.11.2020, 13:31:17 | Сообщение # 6 |  
  
 | 
Цитата GreenBytes (  )   Время выполнения кода было примерно одинаково.  Лог проверял после начала лагов?
  Надо делать несколько sm_dump_handles (в разные файлы) и сравнивать, например: 1.txt с самого начала. 2.txt через x мин (ближе к моменту, когда должны начаться лаги, если известно) 3.txt когда начались лаги
  И sql на TQuery все же стоит перевести, может связь не такая стабильная, как кажется. Это первая/основная из возможных причин зависания и от неё лучше избавиться. 
 | 
 
|   | 
 |    |  
| 
GreenBytes
 | 
Дата: Понедельник, 23.11.2020, 16:17:12 | Сообщение # 7 |  
  
  |  
Сообщений: 19
 
Репутация: 0 [ +/- ]
 |   
 | 
_wS_, я решил сделать методом исключения. Убрал из плагина код map, который самый длинный я присылал в посте ( он там из файла читает и ставит Entity ) Так же убрал скины.
  Сервер работает с утра, не каких багов и зависаний нет. SQL оставил как есть, учитывая что у меня еще чат весь в базу копируется...
  Получается проблема из -за какого -то NPC или Entity который ставит плагин на карту. Теперь необходимо сделать методом исключения в плагине буду по одному Entity добавлять и смотреть на лаги. Жаль что это все занимает очень много времени. Первым делом думаю сразу все Entity которые есть в игре стандартные вывести и по смотреть, после уже загруженные дополнительно на сервер. Т.е проблема не в плагине а толи в движке самого Source толи как -то AI обрабатывается не правильно.
  В любом случае я пишу не только плагины, но и сам сервер на C++, source-sdk... Там пришлось много всего сделать, но это не должно влиять.Добавлено (24.11.2020, 06:43:53) --------------------------------------------- Вернул модуль кода. Сделал чтоб создавались пока что только стандартные объекты, полет нормальный, лагов нет. Добавлено (03.12.2020, 14:12:00) --------------------------------------------- Добрый день. Все -же оказались лаги из -за NPC... Выше на скриншотах видно они у меня используются в качестве магазинов. Удалил NPC лаги все пропали.  
 | 
 
|   | 
 |    |     
		
		
 
 |