shape1
shape2
shape3
shape4
shape7
shape8

Всё о stock


Статус
Закрыто для дальнейших ответов.

Dmitriy_Orell

алкоголик
Пользователь
12.04.2015
977
2
390
0
Определение Stock:

Stock - Маркер компилятора, указывающий компилятору на исключение кода функции из конечного amx файла, если функция не используется в коде скрипта.

 ​

Иными словами код функции или переменные, созданные с использованием маркера "stock", не будут включены в скомпилированную версию мода, если они не будут использованы в моде.
Если же создать функцию/переменную с использованием других маркеров, компилятор включит их в финальную версию, сигнализирует о их бесполезности и AMX машина (сервер) выделит для них память


Способы применения Stock:

1. Переменные:

new



Целочисленный тип

Код:
new variable;
Вещественный тип

Код:
new Float:variable;
Строка

Код:
new variable[10];
Одномерный массив

Код:
new variable[2] = {1, 7};
Двумерный массив

Код:
new variable[2][1] =  { {8},  {15} };
stock

Целочисленный тип

Код:
stock variable;
Вещественный тип

Код:
stock Float:variable;
Строка

Код:
stock variable[10];
Одномерный массив

Код:
stock variable[2] = {1, 7};
Двумерный массив

Код:
stock variable[2][1] = { {8},  {15} };


Использование переменных в stock точно такое же, как и использование переменных в new. В чём же различие, спросите Вы?

А различие именно в том, что stock не регистрируется в памяти сервера. То есть, если переменная объявлена через stock, но в коде она нигде не используется, компилятор автоматически удалит её при компиляции (имеется ввиду то, что в .amx варианте вашего кода этой переменной не будет). Следовательно лишней памяти сервер не будет выделять для этой переменной. Данное правило распространяется и на функции, так что запоминаем сразу (ниже упоминаний об этом не будет).
Но стоит помнить, что Вы никак не узнаете, используется переменная или нет, без ручного поиска кода, в котором используется эта переменная. Ибо, в случае с stock, при компилировании данная ошибка отображаться не будет:

warning 204: symbol is assigned a value that is never used: "%s

2. Функции:

С помощью stock Вы можете единственный раз написать определённый код и после вызывать его всего лишь написав код вызова stock. Но и не только. С помощью stock Вы можете сильно облегчить свою жизнь при написании различных сложных функций :) И ниже я попробую привести несколько примеров кода для того, чтобы Вы поняли о чём я говорю.

Создание stock:
Новый stock создаётся вне других функций (public/stock). То есть, точно так же, как и public, но без forward.

Пример создания stock:

Код:
stock StockName(arguments)
{
    return 1;
}
Где:
StockName - название нашего stock
arguments - название аргументов, в которые будет помещена информация для обработки. Названия могут быть любыми, как и в случае с переменными. Про ограничение на количество этих аргументов в одном stock мне не известно. Если Вы об это что-то знаете, просьба отписаться с предоставлением каких-либо доказательств. Но уж точно не менее 8 аргументов использовать можно.

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

Допустим, у нас есть диалог, который мы используем в нескольких участках кода (одинаковый). Чтобы каждый раз не писать его, мы можем создать stock с ним

Код:
stock ShowDialog(id)
{
    new string[1001];//Да, текст занимает 1001 ячейку. Точнее 1000 ячеек, но нужно же ещё выделить одну для нулевого символа =) И теперь представьте, что если такой диалог нужно вызывать в нескольких местах, каждый раз придется выделять 1001 ячейку. То есть, при создании двух таких переменных, Вы уже выделите 2002 ячейки, при создании трёх - 3003 и т.д. Согласитесь, нерационально это =) (Для самых внимательных: Да, можно создать глобальную переменную. Но зачем забивать мод кучей одинаковых строк, когда можно написать их 1 раз?)
    format(string, sizeof(string), "Тут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock");
    format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
    format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
    format(string, sizeof(string), "%sТут длинный текст, который будет занимать много места в коде. Да и для его хранения придется создавать каждый раз переменную, а это трата памяти. Зачем нам это? Лучше раз создать stock, в котором 1 раз объявить переменную, и уже работать с этим stock",string);
    ShowPlayerDialog(id, 0, DIALOG_STYLE_MSGBOX, "Названия диалога", string, "Кнопа 1", "Кнопа 2");
    return 1;
}
Примечание: Хоть для отображения диалога требуется аргумент "playerid", в stock мы указали имя аргумента "id". Поэтому в ShowPlayerDialog мы должны указать именно "id", а уже при вызове stock мы присвоим значение аргументу "id" значение аргумента "playerid".
Обратите внимание, что "id", при создании stock, я написал лишь для того, чтобы Вы поняли, что имя аргумента может быть любое. Вы можете сразу написать "playerid" и в ShowPlayerDialog использовать "playerid". А можете написать "Deimos_noob" и так же использовать в диалоге уже "Deimos_noob". Главное не забывайте менять название аргумента в нативных функциях (кликабельно) внутри stock на такое, какое Вы указали при создании stock (примером является "id" в создании stock и "playerid" в ShowPlayerDialog). Но менять название нужно именно в тех аргументах, значение которых Вы будете "доставлять" в код, находящийся в stock, при вызове этого stock. В этом примере это был "palyerid" и ниже Вы это увидите

Ну и создадим команду для отображения этого диалога

Код:
if (strcmp("/showmydialogue", cmdtext, true, 10) == 0)
{
    SendClientMessage(playerid,0xFF0000FF,"А вот и диалог");
    ShowDialog(playerid);//Вот тут мы указали откуда именно брать значение для "id". В данном случае в "id" поместится значение ID игрока. Но это может быть и не ID, а та информация, которая вам нужна. Ниже я приведу примеры
}
Ну и при коннекте игрока вызовем диалог

Код:
public OnPlayerConnect(playerid)
{
    ShowDialog(playerid);
    return 1;
}


А теперь попробуем создать команду для передачи денег от одного игрока к другому с помощью stock. Сначала создадим stock с тремя аргументами, в которые запишем ID обоих игроков и сумму передачи денег

Код:
stock PlayerMoneyToPlayer(player1, player2, money)//Опять же, имена аргументов выбираете только Вы. Я создаю такие только для того, чтобы Вы чётко видели что и где менять
{
    new string[71];//57 символов занимает весь текст. Максимальная сумма денег на руках игрока не может превышать 11 символов, поэтому к 57 прибавляем 11 и выделяем 3 ячейки для хранения трёхзначного ID игрока (не видел онлайн в 1000 человек ещё, так что 3 символа хватит). 57 + 11 + 3 = 71 
    GivePlayerMoney(player1,-=money);//Отнимем сумму у игрока, который решил передать деньги
    GivePlayerMoney(player2,+=money);//Выдадим деньги игроку, которому первый игрок решил передать деньги
    format(string,sizeof(string),"Вы передали %d$ игроку с ID %d", money, player2);
    SendClientMessage(player1,0xFFFFFFFF,string);//Оповестим первого игрока о успешной передаче денег
    format(string,sizeof(string),"Вам передали %d$. ID игрока, передавшего вам деньги - %d", money, player2);
    SendClientMessage(player2,0xFFFFFFFF,string);//Оповестим второго игрока о успешном получении денег
    return 1;//Отсылаем серверу сигнал о том, что всё прошло успешно и можно продолжать выполнять код после stock.
}
И теперь создадим команду, в которой и присвоим нужные значения для аргументов stock
Код, требуемый для правильной работы strtok

Код:
if (strcmp("/pay", cmd, true, 10) == 0)
{
    tmp = strtok(cmdtext, idx);//strtok начнёт искать символы после пробела, которые игрок введёт при использовании команды
    if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели ID игрока");//Если игрок не написал ничего после первого пробела - оповестим его об этом и оборвём выполнение команды
    new giveplayerid = strval(tmp);//strval преобразует введённые игроком данные в число. Если игрок введёт текст, strval выдаст значение 0. Запишем в giveplayerid ID игрока, которому надо передать деньги
    if(playerid == giveplayerid) return SendClientMessage(playerid,0xFF0000AA,"Вы ввели свой ID. Себе деньги передать нельзя");//Если игрок ввёл свой ID, оповестим его об этом и не дадим перевести деньги (это делает return)
    if(!IsPlayerConnected(giveplayerid)) return SendClientMessage(playerid,0xFF0000AA,"Данного игрока нет в сети");//Если игрок ввёл ID игрока, которого нет на сервере, оповестим его об этом и не дадим перевести деньги
    tmp = strtok(cmdtext, idx);//Дадим сигнал моду для поиска ещё одного пробела
    if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели сумму для передачи");//Если игрок не написал ничего после второго пробела - оповестим его об этом и оборвём выполнение команды
    new pmoney = strval(tmp);//Запишем сумму, которую игрок введёт после ввода IP
    if(pmoney < GetPlayerMoney(playerid)) return SendClientMessage(playerid,0xFF0000AA,"У вас недостаточно денег на руках для передачи");//Если денег у игрока меньше чем он ввёл в команду, оповестим его об этом и прервём выполнение кода
    //Теперь пора вызывать наш stock. После команды будет объяснение именно этого кода
    PlayerMoneyToPlayer(playerid, giveplayerid, pmoney);//Передаём деньги с помощью stock
    return 1;
}
"playerid" хранит значение ID игрока, который ввёл команду и передаст это значение аргументу "player1" из нашего stock
"giveplayerid" имеет значение ID игрока, которому надо передать деньги и передаст это значение аргументу "player2" из нашего stock
"pmoney" имеет значение суммы денег для передачи и передаст это значение аргументу "money" из нашего stock
Если кто-то не понял то, как я определил это всё, объясню по другому. Ниже будет предоставлен сам stock (таким, каким мы его создали) и способ вызова этого stock. Одинаковым цветом я выделю те аргументы, значения которых передаются от вызова stock к самому stock

stock PlayerMoneyToPlayer(player1, player2, money)
PlayerMoneyToPlayer(playerid, giveplayerid, pmoney);

То есть, аргументы отделяют друг от друга запятыми. Следовательно, при вызове stock, нам нужно расположить аргументы с данными в таком порядке, чтобы нужные данные присвоились нужному аргументу в stock

В данном примере я покажу вам как передать определённый текст с помощью stock на примере команды личных сообщений. Данный stock будет содержать уже аж 5 аргументов, два из которых будут содержать ники игроков, два будут содержать ID и один будет содержать текст. Да, с помощью strok можно и такое

Код:
stock PrivateMessage(name1[], name2[], playerid, giveplayerid, text[])//name1[] и name2[] будут хранить ники, playerid и giveplayerid будут хранить ID игроков, а text[] - текст. Эти скобки - "[]" - означают, что в аргументе будет хранится текст. Все типы аргументов будут описаны ниже
{
    new Message[169];//Создадим массив, в котором будет хранится текст
    format(Message,sizeof(Message),">> %s[%d]: %s",name2,giveplayerid,text);//Оповестим первого игрока таким сообщением о том, что сообщение доставлено второму игроку.
    //Заметьте, что тут мы уже используем name2 и text без скобок. Так же и с остальными типами аргументов (о которых расскажу ниже)
    SendClientMessage(playerid,0xFF0000FF,Message);
    format(Message,sizeof(Message),"<< %s[%d]: %s",name1,playerid,text);//Оповестим второго игрока таким сообщением о том, что первый игрок прислал ему сообщение
    SendClientMessage(giveplayerid,0xFF0000FF,Message);
    return 1;
}
Ну и теперь сама команда

Код:
if(strcmp(cmd, "/pm", true) == 0)
{
    new PlayerName[1][MAX_PLAYER_NAME]);//Создадим двумерный массив для записи ников обоих игроков
    tmp = strtok(cmdtext, idx);//strtok начнёт искать символы после пробела, которые игрок введёт при использовании команды
    if(!strlen(tmp)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели ID игрока");//Если игрок не написал ничего после первого пробела - оповестим его об этом и оборвём выполнение команды
    new giveplayerid = strval(tmp);//strval преобразует введённые игроком данные в число. Если игрок введёт текст, strval выдаст значение 0. Запишем в giveplayerid ID игрока, которому надо передать деньги
    GetPlayerName(playerid, PlayerName[0], MAX_PLAYER_NAME);//Запишем ник первого игрока
    GetPlayerName(giveplayerid, PlayerName[1], MAX_PLAYER_NAME);//Запишем ник второго игрока
    if(playerid == giveplayerid) return SendClientMessage(playerid,0xFF0000AA,"Вы ввели свой ID. Себе писать в личку нельзя");//Если игрок ввёл свой ID, оповестим его об этом и не дадим написать личное сообщение (это делает return)
    if(!IsPlayerConnected(giveplayerid)) return SendClientMessage(playerid,0xFF0000AA,"Данного игрока нет в сети");//Если игрок ввёл ID игрока, которого нет на сервере, оповестим его об этом и не дадим перевести деньги
    //Далее идёт код, который "ищет" введённый игроком текст
    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)) return SendClientMessage(playerid,0xFF0000AA,"Вы не ввели текст сообщения");//Если игрок не написал ничего - оповестим его об этом и оборвём выполнение команды
    if(strlen(result)>128) return SendClientMessage(playerid,0xFF0000AA,"Максимальная длинна сообщения - 128 символов");//При написании stock, мы создали массив Message. Когда я рассчитывал число ячеек, которые мы выделим для записи текста, я предоставил для текста 128 ячеек. Поэтому сделаем ограничение, дабы текст отобразился корректно
    //Всё, что нужно для формирования "вызова" stock, у нас уже имеется. Теперь делаем сам "вызов"
    PrivateMessage(PlayerName[0], PlayerName[1], playerid, giveplayerid, (result));//Формируем и отправляем запрос
    return 1;
}


Этот код нужно вставлять в самое начало паблика OnPlayerCommandText, если его нет. Без него функция srtok работать не будет

Код:
new cmd[128], idx[128], tmp[128];//Создадим переменные, которые нам понадобятся для дальнейшей работы с функцией strtok
cmd = strtok(cmdtext, idx);//


Типы данных для аргументов:

1. Вещественный (дробное число)

Код:
stock StockName(Float:arguments)
"Float:arguments"

2. Логический (bool. То есть true/false)

Код:
stock StockName(bool:arguments)
"bool:arguments"

3. Целочисленный (целые числа)

Код:
stock StockName(arguments)
"arguments"

4. Строковый (символы, то бишь текст)

stock StockName(arguments[])


"arguments[]"

Примечание: Повторюсь, все типы данных работают так же, как и у переменных. Следовательно, использовать их нужно без аргументов ("Float","[]"."bool:"). Пример имеется в примере 3 (извиняюсь за тавтологию).

Прочие виды аргументов:

Ссылка (&):

Данный вид возвращает значения аргумента, получившиеся после выполнения кода функции. (аналогично "return")

Код:
stock StockName(&arguments)
"&arguments"

Код:
stock Calculator(&n_1, &n_2)//Создадим новый stock, в котором оба аргумента будут являться ссылками
{
    n_1 += 3;//К значению первого аргумента прибавим тройку
    n_2 -= 17;//От значения второго аргумента отнимем семнадцать
    return 1;
}//Выполнение кода окончено и все аргументы, созданные как ссылки, вернут свои
Код:
main()
{
    new num[2];
    num[0] = 10;
    num[1] = 20;
    printf("\nДо вызова\nЗначение[0] = %d\nЗначение[1] = %d\n",num[0],num[1]);//До вызова стока значения переменных будут равны заданным ранее значениям
    Calculator(num[0], num[1]);//До вызова переменные будут равны 10 и 20, а после выполнения их значения станут равны 13 и 3
    printf("\nПосле вызова\nЗначение[0] = %d\nЗначение[1] = %d\n",num[0],num[1]);//После вызова значения будут уже другими
}


Автор: DeimoS

 
Последнее редактирование модератором:

denisz

Освоившийся
Пользователь
26.06.2014
294
26
0
23
Скриптер
Хороший урок +

 

LisyFOX

Новичок
Пользователь
22.09.2014
25
0
0
Хорошенько прочитал текст :). Ставлю +,отличный урок!

 

SHOROOP

Освоившийся
Пользователь
30.01.2014
58
56
0
32
Скриптер
Ну зачем, если полезной инфы буквально пять копеек, разбавлять ее ненужной инфой про переменные, работа с которыми ничем не отличается от работы в public-функциях? Зато ничего не сказано о том, что stock-функция не будет видима вне исполняемого бинарника (в отличие от тех же public-функций, которые через CallRemoteFunction() можно вызвать из другого бинаря),

Имхо, такой материал нужно править и править.

 
Статус
Закрыто для дальнейших ответов.