- Регистрация
- 5 Июл 2011
- Сообщения
- 465
- Лучшие ответы
- 0
- Репутация
- 246
Здравствуйте, изначально я опубликовал этот пост на стороннем форуме, но позже решил, что и тут он не навредит.
Итак, для начала нужно поговорить о коллбэке OnPlayerUpdate.
Данный колбэк обновляется очень часто, поэтому использовать его нужно с умом, а ума у вас нету, поэтому лучше не использовать.
На замену хорошо подойдёт таймер с интервалом в 1 секунду.
Вроде с этим можно заканчивать.
Принудительно пару советов:
1. Старайтесь использовать как можно меньше таймеров
2. Если функция используется 1 раз, лучше не создавать её отдельно, а использовать напрямую или через макрос
Теперь перейдём к оптимизации.
1. JIT compiler
В топике, где размещён плагин, размещены и тесты:
Без JIT:
С использованием плагина JIT Compiler:
Ну тут без лишних слов всё итак понятно.
Если вдруг JIT крашит сервер, попробуйте запустить samp-server.exe с параметром ProcDump и укажите .dmp файл для него. Для этого откройте командную строку, перейдите в каталог с вашим сервером и выполните следующую команду:
Официальная тема JIT Compiler v0.3.2:
2. Строки
Почитайте очень полезный урок от Триггера, который объяснит почему нельзя использовать большие стринги [Перейти]
Ни в коем случае не возвращайте в функциях/колбэках строки, подробнее: [Перейти]
3. Возвраты
Возьмём за пример функцию:
Теперь посмотрим как она выглядит в оптимизированном виде:
Обратите внимание на изменения, второй способ работает гораздо быстрее.
4. Циклы
Вот пример оптимизированного цикла:
Это один из способов оптимизации циклов игроков.
Второй (более быстрый) способ от пользователя официального форума Y_Less'а.
Он создал инклуд под названием foreach и сейчас я постараюсь объяснить как им пользоваться.
Пример:
Это очень быстрый метод сканирования игроков, постараюсь объяснить.
Допустим играют на сервере 3 человека, id последнего - 25.
Цикл foreach сделает 3 итерации, в отличии от остальных.
Скачать foreach:
Подключать его легко, закиньте его в папку include в вашей папке с pawno и далее в моде/скрипте/инклуде:
На дворе 21 век и люди придумали новые способы оптимизации, правда представить их я вам не могу.
5. Функции
В стандартном GF функции создаются примерно так:
Есть ещё 2 способа создания функций и они намного быстрее, нежели первый:
Таким образом создавать функции намного удобнее и лучше, кстати, я рекомендую способ напрямую создания функции (Func (playerid, gunid) ), т.к если функция в коде не применялось, то компилятор выдаст warining.
6. Переменные MAX_PLAYERS
Часто сталкивался с таким кодом как:
Дефолтно переменная MAX_PLAYERS равна 500.
Т.е мы создаём массив с 500 ячейками, а если максимальное кол-во слотов на сервере - 100, то для этого используем следующий код:
Вот так, ещё 1 плюс к оптимизации
7. Получение имени игрока
Всё чаще начал замечать следующую функцию для получения ника игрока:
Категорически не рекомендую это использовать, т.к у данной функции есть 2 больших минуса:
1. При каждом использовании объявляется функция PlayerName
2. Функция возвращает строку, а это не хорошо
Вот как можно это оптимизировать, но не упростить:
В энуменатор игроков добавляем переменную:
В public OnPlayerConnect :
Далее ко всем макросам:
#define GN(%1) PlayerInfo[%1][pName]
И всё, теперь без переполнения стека можно определять ник игрока, это очень большой плюс к оптимизации.
Пример использования:
8. Switch vs Оператор ветвления if/else/else if
В большинстве случаев оператор switch выигрывает в скорости.
Switch работает быстрее в тех случаях, когда нужно перебрать большое кол-во значений.
К примеру диалоги, в большинстве модах много диалогов и оператором if их перебирать не разумно.
Приведём пример как было:
и как стало:
В каких случаях лучше использовать switch:
9. Команды
Наиболее быстрый плагин для создания команд - DC_CMD
Вот ссылка: http://pawno-info.ru/showthread.php?t=154792
Если вам не понятно как теперь создавать команды, воспользуйтесь данной темой:
Подробный мануал по использованию: [Перейти]
10. Рейты
Ещё одна немаловажная часть, это рейты.
При правильной настройке снизится пинг, лаги, нагрузка и пр.
Итак, заходим в server.cfg и там:
Если на вашем сервере играет до 100 человек, то:
Если на вашем сервере играет от 100 до 200 игроков, то:
Если же на вашем сервере играет от 200 до 500 игроков, то:
10. Оптимизация потребления памяти
Приведу простой пример оптимизации потребления памяти на переменных.
Возьмём для примера 2 переменные:
1.
2.
heapspace MAX_PLAYERS: 2004
heapspace MAX_PLAYERS char: 504
Результат на лицо.
Однако не спешите ко всем массивам приписывать char, давайте приглядимся.
Фигурные скобки обозначают, что мы обращаемся к байту, а не к ячейке и главной нашей проблемой является то, что 1 байт хранит значения от 0 до 255 (включительно).
А это значит, что использовать char нужно осмотрительно и с умом.
• Ещё 1 урок, написанный мной, сильно поможет вам значительно сэкономить память: [Перейти]
Урок будет пополняться!
Итак, для начала нужно поговорить о коллбэке OnPlayerUpdate.
Данный колбэк обновляется очень часто, поэтому использовать его нужно с умом, а ума у вас нету, поэтому лучше не использовать.
На замену хорошо подойдёт таймер с интервалом в 1 секунду.
Вроде с этим можно заканчивать.
Принудительно пару советов:
1. Старайтесь использовать как можно меньше таймеров
2. Если функция используется 1 раз, лучше не создавать её отдельно, а использовать напрямую или через макрос
Теперь перейдём к оптимизации.
1. JIT compiler
На самом деле JIT Compiler во много раз ускоряет выполнение скрипта (кода).Он переводит AMX байт-код (код созданный компилятором PAWN) в машинный x86-код, во время выполнения, чтобы ускорить выполнение скрипта.
В топике, где размещён плагин, размещены и тесты:
Без JIT:
Код:
Test "floatrandom1" finished: 2684ms (3725782.5/sec)
Test "IsPlayerAimingAt" finished: 3004ms (332889.5/sec)
Test "GetPlayerCameraAimVector" finished: 192ms (5208333.5/sec)
Код:
Test "floatrandom1" finished: 715ms (13986014.0/sec)
Test "IsPlayerAimingAt" finished: 2301ms (434593.6/sec)
Test "GetPlayerCameraAimVector" finished: 22ms (45454548.0/sec)
Если вдруг JIT крашит сервер, попробуйте запустить samp-server.exe с параметром ProcDump и укажите .dmp файл для него. Для этого откройте командную строку, перейдите в каталог с вашим сервером и выполните следующую команду:
PHP:
path/to/procdump.exe -e -ma -x samp-server.exe samp-server.dmp
Чтобы видеть скрытое содержание Зарегистрируйтесь на форуме!
2. Строки
Почитайте очень полезный урок от Триггера, который объяснит почему нельзя использовать большие стринги [Перейти]
Ни в коем случае не возвращайте в функциях/колбэках строки, подробнее: [Перейти]
3. Возвраты
Возьмём за пример функцию:
PHP:
new Float:health;
for (new i = 0; i < MAX_PLAYERS; i++)
{
if IsPlayerConnected(i) *then
{
GetPlayerHealth(i, health);
SetPlayerHealth(i, health + 10.0);
}
}
PHP:
new Float:health;
for (new i, z = GetMaxPlayers(); i != z; i++)
{
if !IsPlayerConnected(i) *then continue; //Если игрок не подключен, то цикл пропустит итерацию
if GetPlayerHealth(i, health) *then SetPlayerHealth(i, health + 10.0);
}
4. Циклы
Вот пример оптимизированного цикла:
PHP:
for(new i=GetMaxPlayers( )-1; i != -1; i--)
{
if !IsPlayerConnected(i) *then continue; //В некоторых случаях лучше поставить проверку на флаг логина (если не залогинен)
//Действие
}
Второй (более быстрый) способ от пользователя официального форума Y_Less'а.
Он создал инклуд под названием foreach и сейчас я постараюсь объяснить как им пользоваться.
Пример:
PHP:
foreach(Player, i)
{
//Действие
}
Допустим играют на сервере 3 человека, id последнего - 25.
Цикл foreach сделает 3 итерации, в отличии от остальных.
Скачать foreach:
Чтобы видеть скрытое содержание Зарегистрируйтесь на форуме!
Подключать его легко, закиньте его в папку include в вашей папке с pawno и далее в моде/скрипте/инклуде:
PHP:
#include foreach
5. Функции
В стандартном GF функции создаются примерно так:
PHP:
forward Func(playerid, gunid);
public Func(playerid, gunid)
{
return true;
}
PHP:
stock Func(playerid, gunid)
{
}
Func(playerid, gunid)
{
}
6. Переменные MAX_PLAYERS
Часто сталкивался с таким кодом как:
PHP:
new Player[MAX_PLAYERS];
public OnPlayerConnect(playerid)
{
Player[playerid] += 1;
}
Т.е мы создаём массив с 500 ячейками, а если максимальное кол-во слотов на сервере - 100, то для этого используем следующий код:
PHP:
#undef MAX_PLAYERS // Раздефайним макрос MAX_PLAYERS
#assert MAX_PLAYERS > 0
#define MAX_PLAYERS = 100; //Объявим константу, равную 100
7. Получение имени игрока
Всё чаще начал замечать следующую функцию для получения ника игрока:
PHP:
forward GN(playerid);
public GN(playerid)
{
new PlayerName[MAX_PLAYER_NAME];
GetPlayerName(playerid,PlayerName,sizeof(PlayerName));
return PlayerName;
}
1. При каждом использовании объявляется функция PlayerName
2. Функция возвращает строку, а это не хорошо
Вот как можно это оптимизировать, но не упростить:
В энуменатор игроков добавляем переменную:
PHP:
pName[MAX_PLAYER_NAME]
PHP:
GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
#define GN(%1) PlayerInfo[%1][pName]
И всё, теперь без переполнения стека можно определять ник игрока, это очень большой плюс к оптимизации.
Пример использования:
PHP:
printf("%s был замечен на сервере", GN(playerid));
8. Switch vs Оператор ветвления if/else/else if
В большинстве случаев оператор switch выигрывает в скорости.
Switch работает быстрее в тех случаях, когда нужно перебрать большое кол-во значений.
К примеру диалоги, в большинстве модах много диалогов и оператором if их перебирать не разумно.
Приведём пример как было:
PHP:
if(dialogid == 100)
{
if(response)
{
if(listitem == 0)
{
print("1");
}
if(listitem == 1)
{
print("1");
}
if(listitem == 2)
{
print("1");
}
if(listitem == 3)
{
print("2");
}
if(listitem == 4)
{
print("3");
}
if(listitem == 5)
{
print("2");
}
}
}
else if(dialogid == DIALOG_LOGIN)
{
if(response)
{
//Действие
}
}
PHP:
switch(dialogid)
{
case 100:
{
if(!response) return true;
switch(listitem)
{
case 0..2: print("1");
case 3,5: print("2");
case 4: print("3");
}
}
case DIALOG_LOGIN:
{
if(!response) return 1;
}
}
Следующая конструкция:
быстрее, чем
Следующая конструкция:
медленнее чем
Следующая конструкция:
одинакова как и
Следующая конструкция:
быстрее чем
PHP:
switch(var)
{
case 40,80,150,160,230,420: return 1;
}
PHP:
if ( var == 40 || var == 80 || var == 150 || var == 160 || var == 230 || var == 420 ) return 1;
PHP:
switch(var)
{
case 40..80,150..160,230..420: return 1;
}
PHP:
if ( var >= 40 && var <= 80 || var >= 150 && var <= 160 || var >= 230 && var <= 420 ) return 1;
PHP:
switch(var)
{
case 40: return 1;
}
PHP:
if ( var == 40 ) return 1;
PHP:
switch(var)
{
case 40..50: return 1;
}
PHP:
if ( var >= 40 && var <= 50 ) return 1;
9. Команды
Наиболее быстрый плагин для создания команд - DC_CMD
Вот ссылка: http://pawno-info.ru/showthread.php?t=154792
Если вам не понятно как теперь создавать команды, воспользуйтесь данной темой:
Подробный мануал по использованию: [Перейти]
10. Рейты
Ещё одна немаловажная часть, это рейты.
При правильной настройке снизится пинг, лаги, нагрузка и пр.
Итак, заходим в server.cfg и там:
Если на вашем сервере играет до 100 человек, то:
PHP:
onfoot_rate 40
incar_rate 40
weapon_rate 40
stream_distance 400.0
stream_rate 500
PHP:
onfoot_rate 40
incar_rate 40
weapon_rate 40
stream_distance 300.0
stream_rate 1000
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 - время в мили секундах за которое будут обновляться данные от игрока к объекту.
incar_rate - время в мили секундах для обновления позиции транспорта на котором ездят игроки.
weapon_rate - время в мили секундах обновления попадания оружия.
stream_distance - расстояние от игрока к объекту в зоне видимости.
stream_rate - время в мили секундах за которое будут обновляться данные от игрока к объекту.
10. Оптимизация потребления памяти
Приведу простой пример оптимизации потребления памяти на переменных.
Возьмём для примера 2 переменные:
1.
PHP:
new a[MAX_PLAYERS];
a[1] = 100;
PHP:
new a[MAX_PLAYERS char];
a{1} = 100;
heapspace MAX_PLAYERS char: 504
Результат на лицо.
Однако не спешите ко всем массивам приписывать char, давайте приглядимся.
Фигурные скобки обозначают, что мы обращаемся к байту, а не к ячейке и главной нашей проблемой является то, что 1 байт хранит значения от 0 до 255 (включительно).
А это значит, что использовать char нужно осмотрительно и с умом.
• Ещё 1 урок, написанный мной, сильно поможет вам значительно сэкономить память: [Перейти]
Урок будет пополняться!
Последнее редактирование: