| 
 
 
	
		
		
			| Подвисает сервер |  |  |  | 
| GreenBytes | Дата: Воскресенье, 22.11.2020, 17:04:11 | Сообщение # 1 |  |   
|  |  | Сообщений: 19 Репутация: 0 [ +/- ]
 |  | Добрый вечер.Я пишу плагины для сервера, но столкнулся с проблемой что сервер спустя некоторое время начинает подглючивать.
 Опыт программировании у меня имеется на множество ЯП, а так-же в веб программировании . Это я к тому что понимаю что пишу в плагине.
 
 Плагин прикрепить я не могу, он состоит из составных частей для удобства к прочтению ну и является полноценным оригиналом.
 
 Начну.
 Умирающая игра: Half-Life 2 DM, Sourcemod.
 
 
 Код meta listListing 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 лаги все пропали.
 |  |  |  |  |  
 |