Заказать игровой сервер Контакты (заказать плагин/исправить ошибки/другое) Пожертвовать Поиск

[ вход ]
[ последние сообщения ]

  • Страница 1 из 1
  • 1
Подвисает сервер
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 лаги все пропали.

 
  • Страница 1 из 1
  • 1
Поиск: