Доступ к архиву

Переход в группу "Пользователь"

300.00 ₽
Одноразовый платёж
Быстрый переход в группу "Пользователи", без надобности написания постов и ожидания.

Покупка дает возможность:
Быть полноправным участником форума
Нормальное копирование кода
Создавать темы
Скачивать файлы
Доступ к архиву Pawno-Info

Оптимизация мода и виды нагрузки на сервер от Mr.Pawn

Статус
В этой теме нельзя размещать новые ответы.

Mr.Pawn

Умник
Здравствуйте, дорогие пользователи P-I, я прочитал много форумов,тем про оптимизацию модов и об нагрузок на серверов самп,и решил написать тему об том что я узнал, думаю, данная статья пойдёт вам в пользу.
Правда лучше прочитать 1 тему,чем 5-10 и не на одном форуме?!Я не говорю что я придумал всю эту перечисленную оптимизацию,я вам даю советы которые узнал за своё пользование в Pawn и советы других программистов.

Старайтесь использовать в моде как можно меньше таймеров, т.к. каждый таймер увеличивает нагрузку на процессор, и сервер требует больше памяти, в случае этого часто у игроков (вылеты), тормозит и падает сервер.

По оптимизацию таймеров я видел не плохой урок, спасибо за это XemyL

Ещё урок от XemyL,по поводу глобальных таймеров - ТЫК

Ссылка на урок – Клабительно (Не реклама)

PHP:
OnPlayerUpdate
не злоупотре***йте этим пабликом, т.к. он обновляется 25 раз в секунду,(как игрок ловит пакеты)да и зависит от пинга игрока, лучше создайте таймер и поместите функцию туда, лучше будет таймер стоять на 1 сек, то есть проверяться 1 раз в секунду, чем будет обновляться этот паблик 25 раз в секунду, а то и больше.

Я часто замечаю многие скриптеры используют функции так:

PHP:
forward Primer(playerid, model);
public Primer(playerid, model)
{
    return true;
}
Но зачем их использовать так?Когда есть более быстрее способ вызвать функцию,через stock,выглядеть это будет вот так:

PHP:
stock  Primer(playerid, model)
{
    return true;
}
Можно вот-так.
PHP:
Primer(playerid, model)
{
    return true;
}
Только вот функции вызываемые через таймер нельзя поместить в stock,можно рассмотреть вот такой вариант:

PHP:
#define fpublic %1(%2) forward %1(%2); public %1(%2)
Данный макрос от OKStyle позволит вам не форвардить функции таймеров,выглядеть это будет так:

PHP:
fpublic Primer(playerid, model)
{
    return true;
}
Согласитесь, этот вариант более проще чем этот:

PHP:
forward Primer(playerid, model);
public Primer(playerid, model)
{
    return true;
}
Теперь приступим к глобальной переменной MAX_PLAYERS и MAX_VEHICLES,по умолчанию в a_samp.inc это значение - (MAX_PLAYERS) равно 500,если даже на хостинге 100 слотов,чтобы это исправить, можно определить значение - (MAX_PLAYERS) по новому:

PHP:
#if defined MAX_PLAYERS 
#undef MAX_PLAYERS 
#define MAX_PLAYERS 100 
#else 
#define MAX_PLAYERS 100 
#endif
Проверка будет выглядеть вот таким видом:

PHP:
new Float:health;
for (new i = 0; i < MAX_PLAYERS; i++)
{
    if (IsPlayerConnected(i))
    {
        GetPlayerHealth(i, health);
        SetPlayerHealth(i, health + 10.0);
    }
}
Есть один минус,вот у нас 100 слотов,а игроков всего 30-40 т.к. мы определили значение - (MAX_PLAYERS) на 100,то у нас будет идти проверка на 100 игроков,ну вот тут есть вот такая функция: GetMaxPlayers(),она определяет онлайн игроков на сервере и сканирует только это количество,на данный момент это 30-40,виглядеть это будет вот так:

PHP:
new Float:health;
for (new i = GetMaxPlayers()-1; i != -1; --i)
{
        if(!IsPlayerConnected(i)) continue;
    if (GetPlayerHealth(i, health)) SetPlayerHealth(i, health + 10.0);
}
Есть один минус,когда у нас будет например 5 игроков с идами: (0,10,15,20,60) то он будет сканировать 61 ид,так вот есть решение это проблемы псевдодинамический массив, для хранения идов подключенных игроков:

В начале мода:

PHP:
new PLIDs[MAX_PLAYERS];
- Создаём глобальный массив
PHP:
new MaxPlayers = 0;
- Переменная содержащая количество игроков на сервере

Очистим весь массив PLIDs,в OnGameModInit:

PHP:
for(new i=0;i<sizeof(PLIDs);i++)
{
    PLIDs[i] = -1;
}
Операции с глобальными переменными,в OnPlayerConnect:

PHP:
PLIDs[MaxPlayers] = playerid; 
MaxPlayers++;
Игрок подключается, и его ид помещается в последнюю свободную ячейку массива PLIDs, ну а переменная MaxPlayers становится на единицу больше.
С пабликом OnPlayerDisconnect все немного сложнее. Игрок выходит, то есть слот в PLIDs который занимала его ид надо очистить.
Но мне не нужен пустой слот, поэтому я присваиваю ему значение самого последнего слота PLIDs, и вот последний уже очищаю:

PHP:
for(new i=0;i<MaxPlayers;i++) 
{ 
    if(PLIDs[i] == playerid) 
    { 
        MaxPlayers--; 
        PLIDs[i] = PLIDs[MaxPlayers]; 
        PLIDs[MaxPlayers] = -1; 
        break; 
    } 
}
Всё,теперь осталось оптимизировать массивы,массив был таким:

PHP:
for(new i=0;i<MAX_PLAYERS;i++) 
{ 
    if(!IsPlayerConnected(i))
    {
    continue;
    } 
    SendClientMessage(i, -1, "Пример"); 
}
После оптимизации:

PHP:
for(new i=0;i<MaxPlayers;i++) 
{ 
    SendClientMessage(PLIDs[i], -1, "Пример"); 
}
Также существует инклюд foreach,он считается более лучшим по оптимизации цыкла игроков.

Урок о фориче- (клабительно)

Использование форича на динамических системах - (клабительно)думаю пригодаться вам,Автор - Пельмень

Также есть Vectoral,он намного быстрее чем форич.
Урок взят с темы: Единая тема оптимизации v1 | v2
Автор урока: Tracker1

Векторы для хранения игроков:
плюсы:
+ БЕШЕННАЯ СКОРОСТЬ ПЕРЕБОРА ВСЕХ ИГРОКОВ.
минусы:
- Твою мать, ни*** не понятно же

#include <Vectoral>

new PLAYERS;

в OnGameModeInit
PLAYERS = cvector();


в соответствующие паблики

public OnPlayerConnect(playerid){ // When player connect
vector_push_back(PLAYERS,playerid); // Insert the player
}

public OnPlayerDisconnect(playerid,reason){
new idx = vector_find(PLAYERS,playerid); // Find player
if(idx !=-1){ // If idx == -1, Vector didn't contains this player
vector_remove(PLAYERS,idx);
}
}
Использование

stock SendMessage(){
for(new idx=0, playerid=0; idx<vector_size(PLAYERS); idx++){ // Цикл
playerid = vector_get(PLAYERS, idx); // Берем плеерид
if(playerid != -1 && GetPlayerTeam(playerid)==NO_TEAM){
SendClientMessage(playerid,0xFFFFAE00,"Чувак, без тимы не круто. Хочешь присоединиться к нам?");
}
}
}

скачать вектора
Теперь давайте поговорим о MAX_VEHICLES,в сампе на данный момент максимум 2000 транспорта,но если у вас 1000 транспорта на сервере то зачем проверять или ещё что либо 2000 транспорта?!
Решение данной проблемы ниже:

PHP:
#undef MAX_VEHICLES //Отключаем стандартное максимальное количество машин
#define MAX_VEHICLES 1000 //Задаём новое значение, 1000 машин
Старайтесь не использовать цыкл в цыкле,пример:

PHP:
for(new i = 0; i < MAX_PLAYERS; i++)
{
    for(new z = 0; z < MAX_PLAYERS; z++)
    {

    }
}
Этот цикл выполнится 500 раз по 500,почему 500?!Потому что глобальная переменная - (MAX_PLAYERS) по умолчанию равна 500,старайтесь не использовать цыкл в цыкле,даже при оптимизации массивов,цыклов,приведёнными выше.

Если вы часто используете один и тот же код,лучше создайте для него функцию,часто это я вижу с GetPlayerName (для узнавания никнейма игрока)пример:

PHP:
stock PlayerName(playerid)
{
	new name[MAX_PLAYER_NAME];
	GetPlayerName(playerid,name,sizeof(name));
	return name;
}
Но опять же мы сталкиваемся с тем что данная функция возвращает строку,а это ведёт к переполнению стека.

Подробней о переполнении стека (клабительно)(Не реклама)

И как же нам быть?!Мы поступим так,как поступил OKStyle:

В enum pInfo добавляем переменную:

PHP:
pName[MAX_PLAYER_NAME]
В public OnPlayerConnect :

PHP:
GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
Теперь мы избавимся от переполнении стека из этой функции,но как её использовать?!

PHP:
new str[50];
format(str, sizeof(str), "%s вышел(ла) из игры (Вылет)", PlayerInfo[playerid][pName]);
SendClientMessageToAll(0xffff00AA, str);
Если,вы хотите использовать более удобней то мы добавим макрос:

PHP:
#define Nick(%1) PlayerInfo[%1][pName]
Пример:

PHP:
new str[50];
format(str, sizeof(str), "%s вышел(ла) из игры (Вылет)", Nick(playerid));
SendClientMessageToAll(0xffff00AA, str);
Вот я замечал на некоторых модах не использую табуляцию кода(лесенку),а просто вставляют функцию: #pragma tabsize 0
Насчёт #pragma tabsize 0,советую её не ставить,пусть у вас будет много ошибок от не ровного кода,чем будет стоять эта функция.
Да и в общем лучше не использовать функции на подобие tabsize,они все грузят мод не хило.
Какая ошибка возникает от не ровного кода?! - warning 217: loose indentation
Пример не ровного кода:

PHP:
if(dialogid == 100)
    {
if(response)
{
if(listitem == 0)
{
printf("1");
    }
    if(listitem == 1)
    {
printf("1");
    }
    if(listitem == 2)
    {
printf("1");
    }
    if(listitem == 3)
    {
        printf("2");
}
    if(listitem == 4)
    {
        printf("3");
    }
if(listitem == 5)
    {
        printf("4");
    }
    }
}
Вот таким он будет табуляционным(лесонкой):

PHP:
if(dialogid == 1)
{
    if(response)
    {
        if(listitem == 0)
        {
            printf("1");
        }
        if(listitem == 1)
        {
            printf("1");
        }
        if(listitem == 2)
        {
            printf("1");
        }
        if(listitem == 3)
        {
            printf("2");
        }
        if(listitem == 4)
        {
            printf("3");
        }
        if(listitem == 5)
        {
            printf("4");
        }
    }
}
if(dialogid == 2)
{
    if(response)
    {
        if(listitem == 0)
        {
            printf("1");
        }
        if(listitem == 1)
        {
            printf("2");
        }
        if(listitem == 2)
        {
            printf("3");
        }
    }
}
Но мы можем этот код оптимизировать,он будет работать намного быстрее,получиться вот так:

PHP:
switch(dialogid)
{
    case 1://Диалог номер один
    {
        if(response)
        {
            switch(listitem)
            {
                case 0: printf("1");
                case 1: printf("1");
                case 2: printf("1");
                case 3: printf("2");
                case 4: printf("3");
                case 5: printf("4");
            }
        }
        else
        {
        //Если в диалоге Кнопка Ок и Отмена,тут будет выполняться действие если нажать отмена,если код пуст от окно закроется
        }
    }
    case 2://Диалог номер 2
    {
        if(response)
        {
            switch(listitem)
            {
                case 0: printf("1");
                case 1: printf("2");
                case 2: printf("3");
            }
        }
        else
        {
        //Если в диалоге Кнопка Ок и Отмена,тут будет выполняться действие если нажать отмена,если код пуст от окно закроется
        }
    }
}
Заметьте этот код и следующий я его немного изменил,так будет ещё лучше:

PHP:
switch(dialogid)
{
    case 1://Диалог номер один
    {
        if(response)
        {
            switch(listitem)
            {
                case 0..2: printf("1");
                case 3..5: printf("%i",listitem-1) ;
            }
        }
        else
        {
        //Если в диалоге Кнопка Ок и Отмена,тут будет выполняться действие если нажать отмена,если код пуст от окно закроется
        return 1;
        }
    }
    case 2://Диалог номер 2
    {
        if(response)
        {
            switch(listitem)
            {
                case 0..2: printf("%i",listitem+1) ;
            }
        }
        else
        {
            //Если в диалоге Кнопка Ок и Отмена,тут будет выполняться действие если нажать отмена,если код пуст от окно закроется
            return 1;
        }
    }
}
Вы наверно хотите узнать подробней о switch,да без проблем,спасибо за это pozitiv4eg (клабительно)(Не реклама)

Многие думают что,если мод оптимизирован то он будет занимать меньше строк,да это так,но смотря при написании чего-либо пример ниже:

PHP:
switch(primer)
{
case 0:
{
//Действие
}
case 1:
{
//Действие
}
case 2:
{
//Действие
}
}
Вот на выше примере,этот код оптимизированный,он занимает 15 строчек.

PHP:
if(primer == 0)
{
//Действие
}
else if(primer == 1)
{
//Действие
}
else if(primer == 2)
{
//Действие
}
Этот код не оптимизированный,но занимает 12 строчек,и работает на много медленнее чем первый,думаю вы поняли что,не главное сколько будет строк в коде,главная суть оптимизации это быстрота и эффективность кода.

При создании массивов типа: string[256]; Подумайте заранее,какая самая большая строка может использоваться в массиве,и максимально уменьшите число в квадратных скобках.
Если вы хотите вывести отформатированное функцией format сообщение в чат,максимальное количество символов в сообщении 144,поэтому не логично использовать string[256];
Я видел тут хороший урок про массивы - спасибо Tracker1 (клабительно)(Не реклама)

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

Часто в модах return в таких формах: return true; и return false; лучше их перевести в данную форму:

PHP:
return 1;// return true
return 0;//return false
Я когда ещё не знал об оптимизации мода,мне посоветовали его оптимизировать и всё будет пучком,ну я стал искать мануалы,и вот наткнулся на public OnPlayerCommandText,загляните в свой public OnPlayerCommandText
Посмотрите код на подобие этого new cmd[256]; new tmp[256];
Вот смотрите:

PHP:
   if(strcmp("/minigun", cmd, true) == 0)
   {
   return GivePlayerWeapon(playerid, 38, 999999);
   }
Вот посмотрите внимательно,перед командой /minigun стоит cmd,массив данной переменной равен 256,но зачем нам 256 ячеек???Когда можно поставить 128,т.к в команде максимально 128 ячеек,для данной команды хватает 8 ячеек,то есть new cmd[8];
В среднем в нормальном моде около 100 команд,представьте сколько нагрузки идёт,давайте посмотрим команду по умолчанию:

PHP:
public OnPlayerCommandText(playerid, cmdtext[])
{
	if (strcmp("/mycommand", cmdtext, true, 10) == 0)
	{
		// Do something here
		return 1;
	}
	return 0;
}
Заметьте там стоит cmdtext а не cmd,переменная cmdtext используется по умолчанию в паблике,если заменить все cmd на cmdtext и убрать переменную с массивом,то будет на много меньше нагрузки.

На счёт команд,я вам точно сказать не могу,на чём они лучше,т.к не проверял.
Как узнаю,обязательно внесу сюда.

Также я замечал многие используют "быдло код" пример ниже:

PHP:
if(Primer[playerid] == 1)
{
SendClientMessage(playerid, -1, "Пример");  
return 1;
}
Ведь можно сделать вот так:

PHP:
if(Primer[playerid] == 1) return SendClientMessage(playerid, -1, "Пример");
Ещё одна немаловажная часть, это рейты,при правильной настройке снизится пинг, лаги, нагрузка и пр.
Итак, заходим в server.cfg и там:

Если на вашем сервере играет до 100 человек, то:
PHP:
onfoot_rate 40
incar_rate 40
weapon_rate 40
stream_distance 400.0
stream_rate 500
Если на вашем сервере играет от 100 до 200 игроков, то:
PHP:
onfoot_rate 40
incar_rate 40
weapon_rate 40
stream_distance 300.0
stream_rate 1000
Если же на вашем сервере играет от 200 до 500 игроков, то:
PHP:
onfoot_rate 50
incar_rate 50
weapon_rate 50
stream_distance 200.0
stream_rate 2000
Перевод:
PHP:
onfoot_rate - время в мили секундах за которое будут обновляться координаты перемещения игроков (в ходьбе).
incar_rate - время в мили секундах для обновления позиции транспорта на котором ездят игроки.
weapon_rate - время в мили секундах обновления попадания оружия.
stream_distance - расстояние от игрока к объекту в зоне видимости.
stream_rate - время в мили секундах за которое будут обновляться данные от игрока к объекту.
На счёт античитов,вообще от них идёт тоже нагрузка,мой совет,убрать их с сервера,пусть админы работают!!!Так будет всем интересней,и есть чем заняться админу,у игроков проявиться интерес обмануть и т.д. в последнее время куда не зайди везде античиты,вспомните раньше года 3 назад,особо не были развиты античиты,да и интерес игры больше был!!!

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

Я вот по сей день стараюсь придерживаться этого,и вам советую поможет в оптимизации.

На сегодня закончим наш урок,со временем буду дорабатывать,обновлять,испровлять тему,ещё раз повторяю я не всё придумал,я сюда внёс основные виды оптимизации,прошу читателей не писать коментарии на подобие этого:
"я проста пздц как умею аптимизировать моды","бред!" "у миня круче метады!" ""

За новые методы (которых здесь нет),я буду только рад,буду давать плюсы и добавлять в первый пост.

С вами был Mr.Pawn
 
Последнее редактирование:
Статус
В этой теме нельзя размещать новые ответы.
Сверху Снизу