31.03.2010, 08:44
Хочу поделиться одной полезной функцией, разработанной мною и Y_Less'ом пару месяцев назад, но не получившей широкого распространения (т.к. опубликована она была лишь в Code Optimisations). С ее помощью можно отправлять отформатированные сообщения игрокам без предварительного вызова format и необходимости содания промежуточного буфера для хранения строки - все это делается внутри нее. До этого реализовать подобную функциональность не получалось из-за проблем с передачей переменного списка аргументов от одной функции другой, теперь она наконец-то решена
Сама конструкция функции позволяет ее без труда изменять для написания других функций с применением данного метода (например, SendFormattedMessageForAll, db_queryf и т.п.).
Внимание! Добавление данной функции в код вашего скрипта может вызывать падение компилятора во время процесса его работы. Чтобы исправить это, необходимо обязательно где-нибудь (по идее неважно где) использовать format в текущем скрипте.
В коде интенсивно используются опкоды абстрактной машины PAWN для доступа к стеку и пр., их описание можно найти в официальной документации (а точнее: http://compuphase.com/pawn/Pawn_Implementer_Guide.pdf).
Пример использования: http://pastebin.com/NbRVdDGM
P.S: возможно еще придется отдефайнить BYTES_PER_CELL дабы убить ошибку:
Сама конструкция функции позволяет ее без труда изменять для написания других функций с применением данного метода (например, SendFormattedMessageForAll, db_queryf и т.п.).
Внимание! Добавление данной функции в код вашего скрипта может вызывать падение компилятора во время процесса его работы. Чтобы исправить это, необходимо обязательно где-нибудь (по идее неважно где) использовать format в текущем скрипте.
В коде интенсивно используются опкоды абстрактной машины PAWN для доступа к стеку и пр., их описание можно найти в официальной документации (а точнее: http://compuphase.com/pawn/Pawn_Implementer_Guide.pdf).
pawn Код:
//
stock SendFormattedMessage(playerid, color, fstring[], {Float, _}:...)
{
// This is the number of parameters which are not variable that are passed
// to this function (i.e. the number of named parameters).
static const
STATIC_ARGS = 3;
// Get the number of variable arguments.
new
n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL;
if (n)
{
new
message[128],
arg_start,
arg_end;
// Load the real address of the last static parameter. Do this by
// loading the address of the last known static parameter and then
// adding the value of [FRM].
#emit CONST.alt fstring
#emit LCTRL 5
#emit ADD
#emit STOR.S.pri arg_start
// Load the address of the last variable parameter. Do this by adding
// the number of variable parameters on the value just loaded.
#emit LOAD.S.alt n
#emit ADD
#emit STOR.S.pri arg_end
// Push the variable arguments. This is done by loading the value of
// each one in reverse order and pushing them. I'd love to be able to
// rewrite this to use the values of pri and alt for comparison,
// instead of having to constantly load and reload two variables.
do
{
#emit LOAD.I
#emit PUSH.pri
arg_end -= BYTES_PER_CELL;
#emit LOAD.S.pri arg_end
}
while (arg_end > arg_start);
// Push the static format parameters.
#emit PUSH.S fstring
#emit PUSH.C 128
#emit PUSH.ADR message
// Now push the number of arguments passed to format, including both
// static and variable ones and call the function.
n += BYTES_PER_CELL * 3;
#emit PUSH.S n
#emit SYSREQ.C format
// Remove all data, including the return value, from the stack.
n += BYTES_PER_CELL;
#emit LCTRL 4
#emit LOAD.S.alt n
#emit ADD
#emit SCTRL 4
return SendClientMessage(playerid, color, message);
}
else
{
return SendClientMessage(playerid, color, fstring);
}
}
Пример использования: http://pastebin.com/NbRVdDGM
P.S: возможно еще придется отдефайнить BYTES_PER_CELL дабы убить ошибку:
pawn Код:
#define BYTES_PER_CELL (cellbits / 8)