[SourcePawn] Урок 15 - API (natives, forwards, functions)

Banana

Участник
Сообщения
892
Реакции
113
@Banana ,
Как то так:
void func()
{
    char szBuffer[MAXPLAYERS+1][PMP];

    //...

    ArrayList aBuffer = ConVertToArrayList(szBuffer, sizeof(szBuffer), sizeof(szBuffer[]));

    Call_StartForward(/*...*/);
    Call_PushCell(aBuffer);
    Call_Finish();

}

ArrayList ConVertToArrayList(const char[][] szBuffer, int iSize, const int iBlockSize)
{
    ArrayList aBuffer = new ArrayList(iBlockSize, 0);

    for(int i; i < iSize; i++)
        aBuffer.PushString(i, szBuffer[i]);

    return aBuffer;
}
Спасибо больше, но я немного ошибся в вопросе мне нужно передать:
SUM_QUESTIONS = 10; //Количество вопросов
INFO_QUESTION = 5; //Текстовые данных вопроса
SizeItem = 128; //Размер текстовых данных

char szBuffer[SUM_QUESTIONS][INFO_QUESTION][SizeItem];

Пожалуйста адаптируйте ваш ответ под эту задачу если вас не затруднит. И сразу вопрос, плагин который получает данные (public) точно увидит этот ArrayList? не нужно передавать права на Handle?
Сообщения автоматически склеены:

ArrayList hArray[10] - можно ли передать в public другого плагина через Forward такой массив данных?
 
Последнее редактирование:

JDW

Мы открываем бизнес
Сообщения
376
Реакции
325
Спасибо больше, но я немного ошибся в вопросе мне нужно передать:
SUM_QUESTIONS = 10; //Количество вопросов
INFO_QUESTION = 5; //Текстовые данных вопроса
SizeItem = 128; //Размер текстовых данных

char szBuffer[SUM_QUESTIONS][INFO_QUESTION][SizeItem];

Пожалуйста адаптируйте ваш ответ под эту задачу если вас не затруднит. И сразу вопрос, плагин который получает данные (public) точно увидит этот ArrayList? не нужно передавать права на Handle?
Сообщения автоматически склеены:

ArrayList hArray[10] - можно ли передать в public другого плагина через Forward такой массив данных?

В данном случае лучше клонировать, чтобы если другой плагин взаимодействует с ArrayList, то в самом плагине не затереть те значения, к котором имеет другой плагин

C-подобный:
Call_PushCell(aBuffer); ->
Call_PushCell(view_as<int>(aBuffer.Clone());
 

iLoco

Пишу плагины за печеньки 🍪🍪🍪
Сообщения
2,265
Реакции
1,323
Вот щас не понял один момент, как создать обратный вызов функции не только для БД, а й к другим. К примеру, плагин 1 создаёт натив, и callback к нему, натив будет добавлять в меню пункт, а в callback должно возвращаться к плагину, который отправил натив первому плагины, название пункта и индекс игрока, который нажал его. Как это провернуть?
 

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #44
как создать обратный вызов функции не только для БД, а й к другим
C-подобный:
typedef MyCallbackType = function void(int somedata);
C-подобный:
Function ptrCallback = GetNativeFunction(x); // x - порядковый номер аргумента, где лежит функция

DataPack hCall = new DataPack();
hCall.WriteCell(hPlugin); // для вызова функции, так же требуется хендл плагина
hCall.WriteFunction(ptrCallback);
C-подобный:
// что-то сделали (сходили в базу асинхронно)
hCall.Reset();
Handle hPlugin = hCall.ReadCell();
Function ptrCallback = hCall.ReadCell();
hCall.Close();

Call_StartFunction(hPlugin, ptrCallback);
Call_PushCell(/* какие-то данные */);
// ...
Call_Finish();
 

Banana

Участник
Сообщения
892
Реакции
113
Подскажите как передать ArrayList[40] массив из 40 элементов через Call_PushArrayEx ?
 

DeathScore13

пирожок. пирожочек.
Сообщения
734
Реакции
403
могу ли я присвоить переменной sString значение string, используя это?

C++:
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
    CreateNative("TestNative", Native_TestNative);
}

public int Native_TestNative(Handle plugin, int numParams)
{
    SetNativeString(1, "string", 8);
}

public void OnPluginStart()
{
    char sString[8];
    TestNative(sString);
}
 

Banana

Участник
Сообщения
892
Реакции
113
h_SPrintToHUD = CreateGlobalForward("SPrintToHUD" ..... ); - обьявлено в нескольких плагинах, нужно в

public SPrintToHUD(....)
{
Как узнать из какого плагине состоялся вызов?
}
 

rejchev

менеджер клоунов
Сообщения
1,669
Реакции
1,291
h_SPrintToHUD = CreateGlobalForward("SPrintToHUD" ..... ); - обьявлено в нескольких плагинах, нужно в

public SPrintToHUD(....)
{
Как узнать из какого плагине состоялся вызов?
}
Передавать указатель в качестве параметра вызова.
 

Banana

Участник
Сообщения
892
Реакции
113
Передавать указатель в качестве параметра вызова.

Передавать указатель в качестве параметра вызова.
PHP:
...
Call_PushCell(GetMyHandle())
...

public SPrintToHUD(...., Handle hRequester)
{
new Handle:hReturnPack = CloneHandle(hPack, hRequester);
А как получить название плагина то?
}

Напишите пример того что вы хотели сказать
 

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #52
Добавляете один параметр с типом Cell, в него передаёте результат вызова GetMyHandle().
 

Nekro

Терра инкогнита
Сообщения
4,025
Реакции
2,260
Ребят подсобите, что то вообще не могу понять как использовать форварды..
Вот моя ахинея, подскажите как исправить, нужно что бы просто был чек события.

C-подобный:
#pragma semicolon 1
#include <weaponfight>
#pragma newdecls required

Handle
    hWeaponFight_DuelStart,
    hWeaponFight_DuelEnd;

public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int iErr_max)
{
    hWeaponFight_DuelStart = CreateGlobalForward("WeaponFight_DuelStart", ET_Event);
    hWeaponFight_DuelEnd = CreateGlobalForward("WeaponFight_DuelEnd", ET_Event);
    
    Call_StartForward(hWeaponFight_DuelStart);
    Call_StartForward(hWeaponFight_DuelEnd);
    Call_Finish();
}

public void Native_StartDuel(Handle hPlugin, int iNumParams)
{
    ServerCommand("sm_cvar sm_revival_enabled 0");
    PrintToChatAll("Плагин Воскрешения отключен на время поидинка !");
}

public int Native_EndDuel(Handle hPlugin, int winner)
{
    ServerCommand("sm_cvar sm_revival_enabled 1");
    PrintToChatAll("Плагин Воскрешения вновь функционирует !");
}

C-подобный:
#if defined _weaponfight_included
 #endinput
#endif
#define _weaponfight_included

/*
    На данный момент запущен Дуэль?
*/
native bool:WeaponFight_IsDuel();

/*
    Событие запуска дуэля.
*/
forward WeaponFight_DuelStart();

/*
    Событие кончания дуэля с номер игрока winner
    winner = 0 игрок вышел с сервера в момент события.
    winner > 0 номер слота игрока, которвый выиграл дуель.
*/
forward WeaponFight_DuelEnd(winner);

public SharedPlugin:__pl_weaponfight =
{
    name = "weaponfight",
    file = "weaponfight",
#if defined REQUIRE_PLUGIN
    required = 1,
#else
    required = 0,
#endif
};

#if !defined REQUIRE_PLUGIN
public __pl_kac_SetNTVOptional()
{
    MarkNativeAsOptional("WeaponFight_IsDuel");
}
#endif
 

Drumanid

Нестандартное звание
Сообщения
1,862
Реакции
1,748
@Nekro,
1614709425161.png
 

Nekro

Терра инкогнита
Сообщения
4,025
Реакции
2,260
Подскажите пожалуйста, вот я отлавливаю событие в одном плагине:

C-подобный:
Handle
    hReset;

public APLRes AskPluginLoad2()
{
    hReset = CreateGlobalForward("Reset", ET_Single, Param_Cell);
}

void Reset(int client)
{
    Call_StartForward(hReset);
    Call_PushCell(client);
    Call_Finish();

    bPlugin[client] = false;
}

inc
C-подобный:
forward int Reset(int client);

А как мне не только отлавливать выполнение этой функции, но и вызывать её в случаи необходимости, и что бы другие плагины так же видели, что функция выполняется?
То есть:
1. Выполняем функцию в ядре
2. Отлавливаем выполнения функции ядра в модуле
3. При необходимости выполняем функцию ядра в модели
4. Другие модули видят выполнение функции ядра (пусть и принудительно вызвано модулем)
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,521
Реакции
4,980
@Nekro, примерно так:
ядро:
Handle hFwd_OnReset;

public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
    CreateNative("Anything_InitReset", Native_InitReset);

    hFwd_OnReset = CreateGlobalForward("Anything_OnReset", ET_Ignore, Param_Cell);

    RegPluginLibrary("anything");

    return APLRes_Success;
}

public int Native_InitReset(Handle plugin, int numParams)
{
    int client = GetNativeCell(1);
    if(client < 1 || client > MaxClients)
        return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index (%d)", client);
    if(!IsClientConnected(client))
        return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not connected", client);
    if(IsFakeClient(client))
        return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is a bot", client);

    InitReset(client);

    return 0;
}

stock void InitReset(int client)
{
    if(!client < 1 | MaxClients < client || !IsClientInGame(client))
        return;

    Call_StartForward(hFwd_OnReset);
    Call_PushCell(client);
    Call_Finish();

    ...    // собственно код сброса
}
инклюд:
/**
 * Reset initiation
 *
 * @param client    Client index
 * @error            Invalid client index, client not connected.
 */
native void Anything_InitReset(int client);

/**
 * Called when the client is reset.
 *
 * @param reviver    Client index
 */
forward void Anything_OnReset(int client);
 

KiKiEEKi

🏆 🥇
Сообщения
653
Реакции
513
Всем привет, есть какой другой способ использование Action глобального форварда.

Что есть:
Есть ядро, есть два глобальных форварда, оба используются в двух модулях.
Каждый модуль в форвардах возвращает Plugin_Continue или Plugin_Handled
Если один модуль вернет в первом форварде Plugin_Handled то в ядре не вызовется второй форвард.
Так как ET_Event и ET_Hook возвращают наивысший результат, в моем случае Plugin_Handled.
А мне нужно что если не один модуль не вернет Plugin_Continue то тогда завершить дальнейшие действия в ядре.

Как это я решил:
Plugin_Continue - это у меня запрещает возвращает false
Plugin_Handled - это возвращает true
Таким вот способом решил проблему.
 

rejchev

менеджер клоунов
Сообщения
1,669
Реакции
1,291
Всем привет, есть какой другой способ использование Action глобального форварда.

Что есть:
Есть ядро, есть два глобальных форварда, оба используются в двух модулях.
Каждый модуль в форвардах возвращает Plugin_Continue или Plugin_Handled
Если один модуль вернет в первом форварде Plugin_Handled то в ядре не вызовется второй форвард.
Так как ET_Event и ET_Hook возвращают наивысший результат, в моем случае Plugin_Handled.
А мне нужно что если не один модуль не вернет Plugin_Continue то тогда завершить дальнейшие действия в ядре.

Как это я решил:
Plugin_Continue - это у меня запрещает возвращает false
Plugin_Handled - это возвращает true
Таким вот способом решил проблему.
Думаю идея понятна (даже char типа хватит на Action)
C-подобный:
// OnSomeFunc
bool SomeForward()
{
    int flags;

    Call_StartForward();
    Call_PushCellRef(flags);
    Call_Finish();

    return (flags & view_as<int>(Plugin_Continue));
}

// <some>.smx
void OnSomeFunc(int& flags)
{
    Action what;

    // some code
  
    flags |= (1 << view_as<int>(what));
}

// <another>.smx
void OnSomeFunc(int& flags)
{
    Action what;

    // some code
  
    flags |= (1 << view_as<int>(what));
}
 

crux

Участник
Сообщения
49
Реакции
4
Здравствуйте! Подскажите, пожалуйста, откуда можно запускать форварды? С OnMapStart() он спокойно отрабатывает, и другой плагин видит, но стоит запустить его с OnPluginStart(), другой плагин этого не видит. Суть в чем, я пытаюсь заставить другие плагины, которые будут работать с основным, "ждать", когда загрузится основной. Если загрузка плагина пройдет успешно, запустить необходимый форвард и дать другим плагинам понять, загрузился ли он нормально или же с ошибкой, ведь другие плагины могут загрузиться раньше основного.
 

Palonez

бб братки
Сообщения
3,035
Реакции
1,837
Здравствуйте! Подскажите, пожалуйста, откуда можно запускать форварды? С OnMapStart() он спокойно отрабатывает, и другой плагин видит, но стоит запустить его с OnPluginStart(), другой плагин этого не видит. Суть в чем, я пытаюсь заставить другие плагины, которые будут работать с основным, "ждать", когда загрузится основной. Если загрузка плагина пройдет успешно, запустить необходимый форвард и дать другим плагинам понять, загрузился ли он нормально или же с ошибкой, ведь другие плагины могут загрузиться раньше основного.
Отсюда, не? AskPluginLoad2
 
Сверху Снизу