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

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

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

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

Оптимизация. [ALL]

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

₥att

Ученик
Оптимизация [ALL]

Приветствую вас дорогие форумчане портала pawno-info.

В этом уроке я попытаюсь более подробно объяснить все виды оптимизаций.

[№1 Оптимизация переменных]:

1.1. Переполненные стоки или как оптимизировать string'и.

Во многих RLS модах при компиляции можно встретить такое:
PHP:
Header size:           4380 bytes
Code size:           215680 bytes
Data size:           226524 bytes
Stack/heap size:      16384 bytes; estimated max. usage: unknown, due to recursion
Total requirements:  462968 bytes
Это говорит о том что в переменных "string" чересчур большой размер массива.

Чтобы исправить это, делаем следующее..
Например..В начале паблика:
PHP:
public OnPlayerCommandText(playerid, cmdtext[])
{
    new string[512]; // создали глобальную переменную размером в 512 ячеек.
}
Теперь в этом же паблике ищем остальные переменные "string" и удаляем, т.к. у нас создана глобальная переменная.

[Важно]: Ищем самый большой format в том паблике, где хотим создать глобальную переменную.
То есть, если в format'е текст в 300 символов, то в начале паблика создаем "new string[356];".​
+1 к оптимизации.​

1.2. Переменные MAX_PLAYERS.

У переменной MAX_PLAYERS дефольно размер массива равен 500 ячейкам, то есть переменная будет работать для первых 500 игроков.
Не у многих серверов онлайн выше 500, так что для первого онлайна лучше сделать следующее:
Ко всем #define:
PHP:
#undef MAX_PLAYERS
const MAX_PLAYERS = 100;
Если онлайн поднялся до 100-150, то констант объявляйте равной в 200.
+1 к оптимизации.​

1.3. format'ы.

Создав одну глобальную переменную "new string[512];"..
fomat лучше будет использовать так:
PHP:
format(string,64,"%s выиграл гонку!",PlayerInfo[playerid][pName])
SendClientMessageToAll(0xFFFFFFAA, string);
чем так:
PHP:
format(string,sizeof(string),"%s выиграл гонку!",PlayerInfo[playerid][pName])
SendClientMessageToAll(0xFFFFFFAA, string);
При запуске возьмет 1КБ от оперативки, а стека брать не будет.
+1 к оптимизации.​

1.4. Получение имени игрока.

Практически в каждом коде можно встретить такое:
PHP:
// почему нету переменной string? 
// -да потому что мы создали глобальную переменную
new sendername[MAX_PLAYER_NAME];
GetPlayerName(playerid, sendername, sizeof(sendername));
format(string, 64, "%s выиграл гонку!", sendername);
SendClientMessageToAll(COLOR_WHITE, string);
COLOR_WHITE - название цвета, то есть можно задефайнить.
Пример..В начале мода:
PHP:
#define COLOR_WHITE 0xFFFFFFAA // Белый
Так, вернемся к оптимизации получения имени игрока. Если постоянно создавать переменные sendername, то можно чокнуться! В смысле категорически не рекомендуется.
Я предлагаю вам версию O.K.Style
В enum pInfo:
PHP:
pName[MAX_PLAYER_NAME]
В public OnPlayerConnect:
PHP:
GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
Теперь все наши "new sendername[MAX_PLAYER_NAME];" и "GetPlayerName(playerid, sendername, sizeof(sendername));" - удаляем.
После..Во всех format'ах "sendername" заменяем на "PlayerInfo[playerid][pName]".
Пример использования:
PHP:
format(string, 64, "%s выиграл гонку!", PlayerInfo[playerid][pName]);
SendClientMessageToAll(COLOR_WHITE, string);
Как видели во многих командах есть "giveplayerid", так вот..Можно и их оптимизировать!
Делаем следующее..
В начале мода:
PHP:
new giveplayer[MAX_PLAYER_NAME];
В начале public OnPlayerCommandText:
PHP:
new giveplayerid; // создали глобальную переменную
В этом же паблике во всех командах удаляем "new giveplayerid;" и "GetPlayerName(giveplayerid, giveplayer, sizeof(giveplayer));".
Затем во всех format'ах "giveplayer" заменяем на "PlayerInfo[giveplayerid][pName]".
Пример использования:
PHP:
format(string,128,"%s был кикнут Администратором %s.",PlayerInfo[giveplayerid][pName],PlayerInfo[playerid][pName]);
SendClientMessageToAll(COLOR_WHITE, string);
Kick(giveplayerid);
Таким образом мы убили 2-ух зайцев, то есть оптимизировали получения имени игрока с двух сторон.
+1 к оптимизации.​

1.5. Пвары.

А вот и еще хороший способ оптимизации переменных!
Давайте рассмотрим принцип работы..Например:
PHP:
if(strcmp(cmd, "/pvar", true) == 0)
{
    new randomlol = random(4);
    switch(randomlol)
    {
        case 0: SetPVarInt(playerid, "lol", 1); // "lol" название переменной. 1 - значение
        case 1: SetPVarInt(playerid, "lol", 2);
        case 2: SetPVarInt(playerid, "lol", 3);
        default: SetPVarInt(playerid, "lol", 4);
    }
    return true;
}
Игроку прицепили переменную lol.
PHP:
if(strcmp(cmd, "/priz", true) == 0)
{
    if(GetPVarInt(playerid, "lol") != 1) return true; // проверка переменной lol. если lol не равняется 1, то никакого действия
    GivePlayerMoney(playerid, 1000);
    DeletePVar(playerid, "lol"); // удалили пвар, то есть отцепили от игрока. а вот с new такие штучки не пройдут!
    return true;
}
Вывод: пвары можно создавать а так же удалять, у пваров маленькая нагрузка, и ими удобно пользоваться.
+1 к оптимизации.​

[№2 Оптимизация циклов]:

2.1. for или foreach?.

Циклы в pawn играют не маловажную роль.
Существует 3 вида цикл. Каждый лучше другого.
[3] Самый отвратительный цикл из всех что я видел:
PHP:
for(new i = 0; i < MAX_PLAYERS; i++)
Но! Существует и оптимизированный цикл, который явно лучше написанного чуть выше.
[2] Оптимизированный цикл:
PHP:
for(new i = GetMaxPlayers() - 1; i != -1; i--)
Да, он хорош, но не с foreach.
foreach - цикл 21 века :)
[1] Самый лучший, самый быстрый, самый самый, цикл foreach.

Скачать инклуд foreach: [ ]
Пароль от скачивания: pawno-info
Установка: Заходим в папку нашего сервера, затем pawno/include/сюда помещаем файл "foreach.inc".

Использовать его можно двумя способами:
PHP:
foreach(Player, i) // 1-ый способ
foreach(new i : Player) // 2-ой способ
Для работы с этим циклом, нам нужно подключить его. То есть ко всем "#include":
PHP:
#include <foreach>
+1 к оптимизации.​

[№3 Оптимизация операторов]:

3.1. switch или if?.

Во сновном оператор switch выигрывает в скорости, чем if.
Switch быстрее только в тех случаях, когда нужно перебрать большое кол-во значений.
Пример не оптимизированных диалогов:
PHP:
if(dialogid == 1)
{
    if(response)
    {
    new listitems[] = "1) Создать пвар\n2) Удалить пвар";//
    ShowPlayerDialog(playerid, 2, DIALOG_STYLE_LIST, "Пвары", listitems, "Выбрать", "Отмена");
    }
}
if(dialogid == 2)
{
    if(response)
    {
    if(listitem == 0)
    {
    SetPVarInt(playerid, "lol", 1);
    SendClientMessage(playerid, COLOR_WHITE, "Ты создал переменную lol.");
    }
    if(listitem == 1)
    {
    DeletePVar(playerid, "lol");
    SendClientMessage(playerid, COLOR_WHITE, "Ты удалил переменную lol.");
    }
    }
    else
    {
    SendClientMessage(playerid, COLOR_WHITE, "Ты выключил меню пваров!");
    }
    return true;
}
А вот как будет выглядеть в оптимизированном виде:
PHP:
switch(dialogid)
{
    case 1:
    {
    if(!response) return true;
    ShowPlayerDialog(playerid, 2, DIALOG_STYLE_LIST, "Пвары", "1) Создать пвар\n2) Удалить пвар", "Выбрать", "Отмена");
    }
    case 2:
    {
    if(!response) return SendClientMessage(playerid, COLOR_WHITE, "Ты выключил меню пваров!");
    switch(listitem)
    {
    case 0: { SetPVarInt(playerid, "lol", 1); SendClientMessage(playerid, COLOR_WHITE, "Ты создал переменную lol."); }
    default: { DeletePVar(playerid, "lol"); SendClientMessage(playerid, COLOR_WHITE, "Ты удалил переменную lol."); }
    }
    }
    return true;
}
Это мы оптимизировали сами диалоги, теперь приведем наглядный пример не оптимизированного оператора if:
PHP:
if(PlayerInfo[playerid][pRassa] == 1) 
{
    PlayerInfo[playerid][pRassa] = 2;
}
if(PlayerInfo[playerid][pRassa] == 3) 
{
    PlayerInfo[playerid][pRassa] = 4;
}
if(PlayerInfo[playerid][pRassa] == 5) 
{
    PlayerInfo[playerid][pRassa] = 6;
}
Можно оптимизировать таким образом:
PHP:
if(PlayerInfo[playerid][pRassa] == 1) PlayerInfo[playerid][pRassa] = 2;
else if(PlayerInfo[playerid][pRassa] == 3) PlayerInfo[playerid][pRassa] = 4;
else if(PlayerInfo[playerid][pRassa] == 5) PlayerInfo[playerid][pRassa] = 6;
Да, оптимизация тут не ахти :)
А теперь давайте оптимизируем оператором switch:
PHP:
switch(PlayerInfo[playerid][pRassa])
{
    case 1: PlayerInfo[playerid][pRassa] = 2;
    case 3: PlayerInfo[playerid][pRassa] = 4;
    case 5: PlayerInfo[playerid][pRassa] = 6;
}
или так:
PHP:
switch(PlayerInfo[playerid][pRassa])
{ 
    case 1,3,5: PlayerInfo[playerid][pRassa]++;
}
+1 к оптимизации.​

3.2. Тернарные операторы.

Тернарный оператор - тоже что и конструкция if..then..else.
Но тернарный оператор применяется в виде одно-строчной функции.

Использование оператора:
логическое выражение ? выражение 1 : выражение 2
Использование конструкцией if..then..else:
if(логическое выражение) then выражение 1 else выражение 2

Наглядный пример использование тернарного оператора:
PHP:
new a, b;
z = (a == 0) ? 0 : 1;
Из этого давайте приведем пример:
PHP:
GivePlayerMoney(playerid, (PlayerInfo[playerid][pCash] > 1000) ? -1000 : SendClientMessage(playerid,COLOR_WHITE,"Недостаточно!"));
Таким образом мы сделали проверку на наличие денег и действие в одну строку!
Можно так:
PHP:
SetPlayerHealth(playerid, (PlayerInfo[playerid][pAdmin] > 1) ? 100.0 : 50.0);
Подобных примеров с данным оператором множество! Надеюсь поняли.
+1 к оптимизации.​

[№4 Оптимизация таймеров]:

Обычный вид таймеров:
PHP:
public OnGameModeInit()
{
    SetTimer("Fuel", 1000, 1);
    SetTimer("Kapt", 1000, 1);
    SetTimer("GiveHP", 1000*2, 1);
    return true;
}
Лучше же конечно использовать все 3 таймера в 1 паблике:
PHP:
public OnGameModeInit()
{
    SetTimer("TimersUpdate", 1000, 1);
    return true;
}
Теперь в него добавляем паблики которые обновляются каждую секунду:
PHP:
Public TimerUpdate() 
{ 
    Fuel();
    Kapt();
    // заметьте! я не добавил паблик "GiveHP" т.к. он обновляется каждые 2 секунды
    return true; 
}
Сам пример использования:
До оптимизации:
PHP:
public OnGameModeInit()
{
    SetTimer("Fuel", 1000, 1);
    SetTimer("Kapt", 1000, 1);
    SetTimer("GiveHP", 1000*2, 1);
    return true;
}

forward Fuel();
Public Fuel()
{
    return true;
}

forward Kapt();
Public Kapt()
{
    return true;
}

forward GiveHP();
Public GiveHP()
{
    return true;
}
После Оптимизации:
PHP:
public OnGameModeInit()
{
    SetTimer("TimersUpdate", 1000, 1);
    SetTimer("GiveHP", 1000*2, 1);
    return true;
}

forward TimersUpdate();
Public TimersUpdate() 
{ 
    Fuel(); 
    Kapt(); 
    return true; 
} 

stock Fuel()
{
    return true;
}

stock Kapt()
{
    return true;
}

forward GiveHP();
Public GiveHP()
{
    return true;
}
Вывод: таким способом, лучше оптимизировать таймеры которые обновляются с одним и тем же временем!
+1 к оптимизации.​

[№5 Оптимизация функций]:

Обычно стандартные функции создаются так:
PHP:
forward Lol(playerid, vehicleid);
public Lol(playerid)
{
    return true;
}
Мне кажется это как то стремно..
И снова я предлагаю вам версию O.K.Style
Ко всем "#define":
PHP:
#define dpublic %1(%2) forward %1(%2); public %1(%2)
То есть мы создали макрос, благодаря которому нам не придется создавать forward'ы.
Использование макроса:
PHP:
dpublic Lol(playerid, vehicleid)
{
    return true;
}
+1 к оптимизации.​

[№6 Оптимизация рейтов в server.cfg]:

Давайте вспомним что говорил Doc_Slove:
"Ещё одна немаловажная часть, это рейты.
При правильной настройке снизится пинг, лаги, нагрузка и пр."

Все правильно, поэтому я и предложу вам его настройки server'a.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
onfoot_rate - время в мили секундах за которое будут обновляться координаты перемещения игроков (в ходьбе).
incar_rate - время в мили секундах для обновления позиции транспорта на котором ездят игроки.
weapon_rate - время в мили секундах обновления попадания оружия.
stream_distance - расстояние от игрока к объекту в зоне видимости.
stream_rate - время в мили секундах за которое будут обновляться данные от игрока к объекту.
+1 к оптимизации.​

[Практика] Оптимизация кода:

Теория теорией, а без практики никуда.
Давайте все выше прочитанное испробуем на команде kick.
[1] Не оптимизированная команда /kick:
PHP:
if(strcmp(cmd, "/kick", true) == 0)
{
    if(IsPlayerConnected(playerid))
    {
    tmp = strtok(cmdtext, idx);
    if(!strlen(tmp))
    {
    SendClientMessage(playerid, COLOR_GRAD2, "{ffffff}*Используйте: /kick [ID игрока] [Причина]");
    return 1;
    }
    new sendername[MAX_PLAYER_NAME];
    new giveplayer[MAX_PLAYER_NAME];
    new giveplayerid;
    giveplayerid = ReturnUser(tmp);
    if(PlayerInfo[playerid][pAdmin] >= 1)
    {
    if(IsPlayerConnected(giveplayerid))
    {
    if(giveplayerid != INVALID_PLAYER_ID)
    {
    GetPlayerName(giveplayerid, giveplayer, sizeof(giveplayer));
    GetPlayerName(playerid, sendername, sizeof(sendername));
    new length = strlen(cmdtext);
    while ((idx < length) && (cmdtext[idx] <= ' '))
    {
    idx++;
    }
    new offset = idx;
    new result[64];
    while ((idx < length) && ((idx - offset) < (sizeof(result) - 1)))
    {
    result[idx - offset] = cmdtext[idx];
    idx++;
    }
    result[idx - offset] = EOS;
    if(!strlen(result))
    {
    SendClientMessage(playerid, COLOR_GRAD2, "{ffffff}* Помощь: /kick [ID игрока] [Причина]");
    return 1;
    }
    format(string, sizeof(string), "%s был кикнут администратором %s, Причина: %s", giveplayer, sendername, (result));
    SendClientMessageToAll(COLOR_LIGHTRED, string);
    Kick(giveplayerid);
    return 1;
    }
    }
    }
    else
    {
    format(string, sizeof(string), "%d не в сети", giveplayerid);
    SendClientMessage(playerid, COLOR_GRAD1, string);
    }
    }
    }
    return true;
}
Посмотрев на этот код, захочется повеситься :)
Теперь давайте оптимизируем код:
PHP:
if(strcmp(cmd, "/kick", true) == 0)
{
    if(!IsPlayerConnected(playerid)) return true;
    if(PlayerInfo[playerid][pAdmin] == 0) return true;
    tmp = strtok(cmdtext, idx);
    if(!strlen(tmp)) return SendClientMessage(playerid, COLOR_GRAD2, "{ffffff}*Используйте: /kick [ID игрока] [Причина]");
    giveplayerid = ReturnUser(tmp);
    if(!IsPlayerConnected(giveplayerid)) return true;
    if(giveplayerid == playerid) return SendClientMessage(playerid, COLOR_WHITE, "[Ошибка] Вы ввели свой ID.");
    new length = strlen(cmdtext);
    while ((idx < length) && (cmdtext[idx] <= ' '))
    {
    idx++;
    }
    new offset = idx;
    while ((idx < length) && ((idx - offset) < (sizeof(result) - 1)))
    {
    result[idx - offset] = cmdtext[idx];
    idx++;
    }
    result[idx - offset] = EOS;
    if(!strlen(result)) return SendClientMessage(playerid, COLOR_GRAD2, "{ffffff}* Помощь: /kick [ID игрока] [Причина]");
    format(string, 128, "%s был кикнут администратором %s, Причина: %s", PlayerInfo[giveplayerid][pName], PlayerInfo[playerid][pName], result);
    SendClientMessageToAll(COLOR_LIGHTRED, string);
    Kick(giveplayerid);
    return true;
}
Вы спросите, куда делись переменные: new giveplayerid,result[64],sendername[MAX_PLAYER_NAME],giveplayer[MAX_PLAYER_NAME];
Ответ прост! Они в начале паблика, кроме sendername,giveplayer. Получается эти переменные - глобальные.

Вот в принципе и все.
Всем спасибо.

[HR][/HR]
Автор данной статьи - Я. ©
Копипаст строго запрещен!​
Подпись: ₥эт​
 
Последнее редактирование:
Статус
В этой теме нельзя размещать новые ответы.
Сверху Снизу