PDA

Просмотр полной версии : [Function] ClearKillFeed - очистка списка убийств



Daniel_Cortez
21.05.2015, 19:46
Описание:

Очищает килл-лист указанного игрока (или всех игроков, если игрок не указан).

Параметры:

playerid - игрок, у которого будет очищен килл-лист (необязательный параметр)


Возвращаемое значение:

Если указан ID игрока, возвращает 0, если он не подключен. В остальных случаях возвращает 1.

Плюсы реализации:

Простота в использовании.
Пониженное потребление пространства в стеке и меньшая нагрузка от функции на сервер за счёт использования #emit.
Работает даже тогда, когда подключены все игроки.

Код:

stock ClearKillFeed(playerid = INVALID_PLAYER_ID)
{// by Londlem & Daniel_Cortez \\ pro-pawn.ru
if((playerid != INVALID_PLAYER_ID) && (0 == IsPlayerConnected(playerid)))
return 0;
goto L_start;
// avoid possible stack overflow (due to using push.* opcodes)
{
new dummy[16/(cellbits/charbits)];
#emit const.pri dummy
}
#if __Pawn < 0x030A
// optional sysreq.c bugfix
SendDeathMessage(0, 0, 0),
SendDeathMessageToPlayer(0, 0, 0, 0);
#endif
L_start:
const CKF_MAGIC_ID = INVALID_PLAYER_ID - 1;
// this variable is also used as weaponid parameter
new i = 5;
// push killer and killee IDs
#emit push.c CKF_MAGIC_ID
#emit push.c CKF_MAGIC_ID
if(playerid == INVALID_PLAYER_ID)
{
#emit push.c 12
do{
#emit sysreq.c SendDeathMessage
}while(--i != 0);
#emit stack 12
}
else
{
#emit push.s playerid
#emit push.c 16
do{
#emit sysreq.c SendDeathMessageToPlayer
}while(--i != 0);
#emit stack 16
}
return 1;
}


Примечания:
Для очистки киллчата в качестве ID убитого игрока используется значение INVALID_PLAYER_ID-1.
Значение это получено опытным путём благодаря Londlem'у.
Можно было использовать ID любого неподключенного игрока от 0 до 999, но такая реализация была бы ненадёжной, т.к. всё равно оставалась бы вероятность, что подключены будут все 1000 игроков и свободных слотов для SendDeathMessage не останется.
Также был вариант использовать INVALID_PLAYER_ID, но этот вариант не работал.
В англоязычной документации (http://wiki.sa-mp.com/wiki/SendDeathMessage) сказано, что для работы функции нужно передать любой валидный ID убитого игрока (т.е. от 0 до 999).
Тем не менее, опытным путём было замечено, что ID от 1000 до INVALID_PLAYER_ID-1 тоже работают.
На самом деле это баг, но куй вряд ли исправит его - сервер из-за этого бага не крашит, да и игроки тоже, а значит можно, как всегда, забить.
Поскольку кол-во слотов с новыми релизами SA:MP может увеличиться, самым безопасным вариантом будет использовать наибольшее рабочее значение - INVALID_PLAYER_ID-1.


Пример использования:

CMD:cleardeaths(playerid, params[])
{
ClearKillFeed(playerid);
return SendClientMessage(playerid, -1, "Список убийств очищен.");
}



Автор: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)

Благодарности:
Londlem (http://pro-pawn.ru/member.php?2057-Londlem) - за идею с использованием INVALID_PLAYER_ID-1.
Kalcor - за то, что с каждым выпуском SA:MP плодит всё больше багов (в т.ч. и баг с возможностью юзать ID больше 999 в SendDeathMessage).



Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!

Desulaid
21.05.2015, 20:36
Kalcor такой молодец. И баги у него все интереснее и интереснее.:mosking:
А так эта функция идеально подходит мне для разработки одного мода. Как раз лишней не будет :grin:

wAx
21.05.2015, 20:48
Как всегда, работа на уровне!

Desulaid
01.06.2015, 21:55
Ты предал свои же стандарты((9(


// ..
do{
#emit sysreq.c SendDeathMessage
}while(--i != 0);
// ..
do{
#emit sysreq.c SendDeathMessageToPlayer
}while(--i != 0);
// ..

$continue$
01.06.2015, 22:22
Ты предал свои же стандарты((9(


// ..
do{
#emit sysreq.c SendDeathMessage
}while(--i != 0);
// ..
do{
#emit sysreq.c SendDeathMessageToPlayer
}while(--i != 0);
// ..


Какие стандарты?

123
08.08.2016, 17:44
После выхода, как я понял, килл-лист не очищается? Нужно очищать самостоятельно?

VVWVV
17.07.2018, 23:14
Быть может сделать версию для оператора __emit без всяких workarounds.

Daniel_Cortez
18.07.2018, 08:32
Быть может сделать версию для оператора __emit без всяких workarounds.
Не вижу смысла. От вызова IsPlayerConnected() не избавиться, SendDeathMessageToPlayer() возвращает 1 даже когда игрок не подключен. Объявление массива тоже нужно, чтобы компилятор правильно подсчитал использование стека при вызове нативных функций (не уверен, возможно ли заставить оператор emit считать его самостоятельно). Единственное, что можно убрать - это пустые вызовы SendDeathMessage() и SendDeathMessageToPlayer() - и только ради этого вместо стокового компилятора требовать новую версию? Едва ли стоит того.

VVWVV
18.07.2018, 13:17
Кстати, а почему в инструкциях stack значения равные размеру переданных элементов в стеке? Там же должно быть на 4 больше,ибо пушим размер аргументов в стеке.

Daniel_Cortez
18.07.2018, 18:28
Кстати, а почему в инструкциях stack значения равные размеру переданных элементов в стеке? Там же должно быть на 4 больше,ибо пушим размер аргументов в стеке.
Потому что одним из аргументов (ID оружия) для SendDeathMessage(ToPlayer) является переменная i - таким образом, в неё совмещено сразу два назначения. А поскольку она уже есть в стеке, нет смысла копировать её значение туда ещё раз.

VVWVV
18.07.2018, 18:46
Потому что одним из аргументов (ID оружия) для SendDeathMessage(ToPlayer) является переменная i - таким образом, в неё совмещено сразу два назначения. А поскольку она уже есть в стеке, нет смысла копировать её значение туда ещё раз.

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

Daniel_Cortez
19.07.2018, 16:46
Как по мне, это может запутать (тебе аж пришлось писать комментарий для этого), лучше вынести в инструкцию.
Можно вообще всю функцию без единого #emit переписать, там от этого толку немного, учитывая специфичность самой функции и то, как нечасто она будет использоваться (лично мне приходит в голову только вариант с командой очистки киллфида для администраторов). Моей задачей было просто показать оптимизационные приёмы, которые до этого ни разу не приходилось наблюдать на практике - авось, кто-нибудь да найдёт им достойное применение.

scory
25.04.2020, 04:50
А чем отличается от этого?


for(new i = 0; i < 5; i++) SendDeathMessageToPlayer(playerid, INVALID_PLAYER_ID, INVALID_PLAYER_ID, WEAPONSTATE_UNKNOWN);

SteveStage
25.04.2020, 15:53
А чем отличается от этого?


for(new i = 0; i < 5; i++) SendDeathMessageToPlayer(playerid, INVALID_PLAYER_ID, INVALID_PLAYER_ID, WEAPONSTATE_UNKNOWN);

В описании все было:


Плюсы реализации:

Простота в использовании.
Пониженное потребление пространства в стеке и меньшая нагрузка от функции на сервер за счёт использования #emit.
Работает даже тогда, когда подключены все игроки.