Подвисает сервер
| |
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 лаги все пропали.
|
|
| |
|