Другое SAMPFUNCS | API C++

Ya Zaregalsya

Известный
387
132
Как получить возвращаемое значение SF->getCLEO()->callOpcode() если это не буль?

C++:
pVehicle->pGTAVehicle = GAME->GetPools()->AddVehicle(static_cast<eVehicleTypes>(pVehicle->modelId), NULL, NULL);
Крашит на некоторых моделях машин. Если 560 или 400, то всё ок, если 578, то краш. В чём может быть проблема?
Забыл подгрузить модельку, теперь всё ок. Некоторые модели предзагружаются на старте игры, поэтому глюк может всплыть коварным образом:
C++:
SF->getSAMP()->registerChatCommand("spawnveh", [](std::string param)->void
            {
                int modelId = std::stoi(param);
                CVector spawnPos = DevKit::getActorPos(PLAYER_PED);
                if (!GAME->GetStreaming()->HasModelLoaded(modelId))
                {
                    GAME->GetStreaming()->RequestModel(modelId, 0);
                    GAME->GetStreaming()->LoadAllRequestedModels();
                }
                CVehicle* pVehicle = GAME->GetPools()->AddVehicle(static_cast<eVehicleTypes>(modelId), NULL, NULL);
                pVehicle->SetPosition(&spawnPos);
                GAME->GetWorld()->Add(pVehicle, CObject_Constructor);

            });
 
Последнее редактирование:

Ya Zaregalsya

Известный
387
132
Есть исходники как читать рпс InitGame?

Upd:
C++:
void InitGame(RPCParameters *rpcParams)
{
    PCHAR Data = reinterpret_cast<PCHAR>(rpcParams->input);
    int iBitLength = rpcParams->numberOfBitsOfData;

    RakNet::BitStream bsInitGame((unsigned char *)Data,(iBitLength/8)+1,false);

    PLAYERID MyPlayerID;
    bool bLanMode, bStuntBonus;
    BYTE byteVehicleModels[212];

    bool m_bZoneNames, m_bUseCJWalk, m_bAllowWeapons, m_bLimitGlobalChatRadius;
    float m_fGlobalChatRadius, m_fNameTagDrawDistance;
    bool m_bDisableEnterExits, m_bNameTagLOS, m_bManualVehicleEngineAndLight;
    bool m_bShowPlayerTags;
    int m_iShowPlayerMarkers;
    BYTE m_byteWorldTime, m_byteWeather;
    float m_fGravity;
    int m_iDeathDropMoney;
    bool m_bInstagib;

    bsInitGame.ReadCompressed(m_bZoneNames);
    bsInitGame.ReadCompressed(m_bUseCJWalk);
    bsInitGame.ReadCompressed(m_bAllowWeapons);
    bsInitGame.ReadCompressed(m_bLimitGlobalChatRadius);
    bsInitGame.Read(m_fGlobalChatRadius);
    bsInitGame.ReadCompressed(bStuntBonus);
    bsInitGame.Read(m_fNameTagDrawDistance);
    bsInitGame.ReadCompressed(m_bDisableEnterExits);
    bsInitGame.ReadCompressed(m_bNameTagLOS);
    bsInitGame.ReadCompressed(m_bManualVehicleEngineAndLight); //
    bsInitGame.Read(iSpawnsAvailable);
    bsInitGame.Read(MyPlayerID);
    bsInitGame.ReadCompressed(m_bShowPlayerTags);
    bsInitGame.Read(m_iShowPlayerMarkers);
    bsInitGame.Read(m_byteWorldTime);
    bsInitGame.Read(m_byteWeather);
    bsInitGame.Read(m_fGravity);
    bsInitGame.ReadCompressed(bLanMode);
    bsInitGame.Read(m_iDeathDropMoney);
    bsInitGame.ReadCompressed(m_bInstagib);

    // Server's send rate restrictions
    if(!settings.uiForceCustomSendRates)
    {
        bsInitGame.Read(iNetModeNormalOnfootSendRate);
        bsInitGame.Read(iNetModeNormalIncarSendRate);
        bsInitGame.Read(iNetModeFiringSendRate);
        bsInitGame.Read(iNetModeSendMultiplier);
    }
    else
        bsInitGame.SetReadOffset(bsInitGame.GetReadOffset() + 4*32);

    bsInitGame.Read(m_bLagCompensation);

    BYTE unk;
    bsInitGame.Read(unk);
    bsInitGame.Read(unk);
    bsInitGame.Read(unk);

    BYTE byteStrLen;
    bsInitGame.Read(byteStrLen);
    if(byteStrLen)
    {
        memset(g_szHostName,0,sizeof(g_szHostName));
        bsInitGame.Read(g_szHostName, byteStrLen);
    }
    g_szHostName[byteStrLen] = '\0';

    bsInitGame.Read((char *)&byteVehicleModels[0],212);

    g_myPlayerID = MyPlayerID;

    char szTitle[64];
    if(settings.iConsole)
    {
        sprintf(szTitle, "%s (%d) - %.16s - RakSAMP %s", g_szNickName, g_myPlayerID, g_szHostName, RAKSAMP_VERSION);
        SetConsoleTitle(szTitle);
        Log("Connected to %.64s\n", g_szHostName);
    }
    else
    {
        sprintf(szTitle, "%s (%d) - RakSAMP %s", g_szNickName, g_myPlayerID, RAKSAMP_VERSION);
        SetWindowText(hwnd, szTitle);
        Log("Connected to %.64s", g_szHostName);
    }

    iGameInited = 1;
}
 
Последнее редактирование:

walkerdev

Новичок
7
0
Как установить усталость игроку?
Т.е., установить stamina (выносливость) для игрока, у которого запущен данных SF скрипт.
И вопрос, при установке его скорость бега будет видна только ему, или всем игрокам? (быстро бежит/уставший)
 

chopisat

Новичок
17
0
1737309606894.png


при сборке выдает такое
причем собираю только что сбилженный по симейку, который идем в sampfuncs sdk последней версии
 

FYP

Известный
Администратор
1,768
5,979

TheLeftExit

Участник
35
15
Можно как-то попросить у мейнтейнеров плагина изменить SF->getSAMP()->registerChatCommand, или добавить альтернативную апишку, чтобы CommandProc принимал char* или что-то другое, что можно безопасно побитно передать в не-C++ языки, а не std::string? Пишу C# враппер, и пока что большинство простых задач из C++ получается через свои методы завернуть в указатели на функции, но тут SF безусловно требует указатель на функцию с C++ классом в сигнатуре. Тот же registerDialogCallback нормально пробрасывается.
 

Musaigen

dead eyes
Проверенный
1,675
1,503
Можно как-то попросить у мейнтейнеров плагина изменить SF->getSAMP()->registerChatCommand, или добавить альтернативную апишку, чтобы CommandProc принимал char* или что-то другое, что можно безопасно побитно передать в не-C++ языки, а не std::string? Пишу C# враппер, и пока что большинство простых задач из C++ получается через свои методы завернуть в указатели на функции, но тут SF безусловно требует указатель на функцию с C++ классом в сигнатуре. Тот же registerDialogCallback нормально пробрасывается.
std::string::data()
 

TheLeftExit

Участник
35
15
Твоё решение позволяет внутри C++ зарегать колбек из другого языка (регистрируем свой void(string), внутри дёргаем data/c_str, полученную строку передаём в C#/другой язык). Для этого нужно на каждую команду, которую я хочу зарегистрировать, писать отдельную функцию-враппер в C++ проекте. Я хочу этого избежать, т.к. иначе приходится в свой C++ проект писать такую гадость для импорта N разных команд.

C++:
#define COMMAND_NAMESPACE CommandBindings
#define DEFINE_COMMAND(entryPointName) \
    namespace COMMAND_NAMESPACE { \
        static CSharpCommandCallback entryPointName; \
        void Load##entryPointName() { entryPointName = GetCommandCallback(#entryPointName); } \
        void __stdcall On##entryPointName(std::string text) { entryPointName(text.c_str()); } \
    }
#define REGISTER_COMMAND(commandName, entryPointName) \
    COMMAND_NAMESPACE::Load##entryPointName(); \
    SF->getSAMP()->registerChatCommand(commandName, CommandBindings::On##entryPointName);

DEFINE_COMMAND(Test1);
DEFINE_COMMAND(Test2);
DEFINE_COMMAND(Test3);
static void RegisterChatCommands() {
    REGISTER_COMMAND("sfsharptest1", Test1);
    REGISTER_COMMAND("sfsharptest2", Test2);
    REGISTER_COMMAND("sfsharptest2", Test2);
}

Я хочу вместо этого единожды экспортировать в C# код одну функцию, и внутри C# регистрировать что и сколько влезет. Как-то так:

C++:
static void __stdcall RegisterChatCommand(char* commandName, void(__stdcall* commandProc)(std::string params)) {
    SF->getSAMP()->registerChatCommand(commandName, commandProc);
}

// Этот указатель улетает в C#
void(__stdcall* registerChatCommand)(char*, void(__stdcall*)(std::string params)) = RegisterChatCommand;
C#:
private static delegate* unmanaged[Stdcall]<byte*, delegate* unmanaged[Stdcall]<WHICHTYPE, void>, void> registerChatCommand;
public static void ExampleCode()
{
    ReadOnlySpan<byte> commandName = "Hello!"u8;
    fixed(byte* pCommandName = commandName)
    {
        registerChatCommand(pCommandName, &OnChatCommand);
    }
}
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
public static void OnChatCommand(WHICHTYPE text)
{
    SF.LogToChat("OnChatCommand");
}
На месте WHICHTYPE должен быть std::string, но этот класс невозможно передавать между языками как битную структуру без отстрела ноги. Если бы вместо string был char*, вместо WHICHTYPE был бы byte* и всё было бы в шоколаде.

Это всё никому кроме меня наверное не надо, но и повода тут использовать string вместо char* я тоже не вижу.
 

AdCKuY_DpO4uLa

Адский дрочер
Друг
350
763
Твоё решение позволяет внутри C++ зарегать колбек из другого языка (регистрируем свой void(string), внутри дёргаем data/c_str, полученную строку передаём в C#/другой язык). Для этого нужно на каждую команду, которую я хочу зарегистрировать, писать отдельную функцию-враппер в C++ проекте. Я хочу этого избежать, т.к. иначе приходится в свой C++ проект писать такую гадость для импорта N разных команд.

C++:
#define COMMAND_NAMESPACE CommandBindings
#define DEFINE_COMMAND(entryPointName) \
    namespace COMMAND_NAMESPACE { \
        static CSharpCommandCallback entryPointName; \
        void Load##entryPointName() { entryPointName = GetCommandCallback(#entryPointName); } \
        void __stdcall On##entryPointName(std::string text) { entryPointName(text.c_str()); } \
    }
#define REGISTER_COMMAND(commandName, entryPointName) \
    COMMAND_NAMESPACE::Load##entryPointName(); \
    SF->getSAMP()->registerChatCommand(commandName, CommandBindings::On##entryPointName);

DEFINE_COMMAND(Test1);
DEFINE_COMMAND(Test2);
DEFINE_COMMAND(Test3);
static void RegisterChatCommands() {
    REGISTER_COMMAND("sfsharptest1", Test1);
    REGISTER_COMMAND("sfsharptest2", Test2);
    REGISTER_COMMAND("sfsharptest2", Test2);
}

Я хочу вместо этого единожды экспортировать в C# код одну функцию, и внутри C# регистрировать что и сколько влезет. Как-то так:

C++:
static void __stdcall RegisterChatCommand(char* commandName, void(__stdcall* commandProc)(std::string params)) {
    SF->getSAMP()->registerChatCommand(commandName, commandProc);
}

// Этот указатель улетает в C#
void(__stdcall* registerChatCommand)(char*, void(__stdcall*)(std::string params)) = RegisterChatCommand;
C#:
private static delegate* unmanaged[Stdcall]<byte*, delegate* unmanaged[Stdcall]<WHICHTYPE, void>, void> registerChatCommand;
public static void ExampleCode()
{
    ReadOnlySpan<byte> commandName = "Hello!"u8;
    fixed(byte* pCommandName = commandName)
    {
        registerChatCommand(pCommandName, &OnChatCommand);
    }
}
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
public static void OnChatCommand(WHICHTYPE text)
{
    SF.LogToChat("OnChatCommand");
}
На месте WHICHTYPE должен быть std::string, но этот класс невозможно передавать между языками как битную структуру без отстрела ноги. Если бы вместо string был char*, вместо WHICHTYPE был бы byte* и всё было бы в шоколаде.

Это всё никому кроме меня наверное не надо, но и повода тут использовать string вместо char* я тоже не вижу.
У sampfuncs есть свой обработчик команд, который и используется в registerChatCommand. Если тебе не принципиально, где будет зарегистрирована команда (в sf или в самом samp), то можно использовать AddClientCommand, который закинет твою команду в пул команд сампа (макс. 144)


C++:
typedef void(__cdecl *CMDPROC) (PCHAR);
struct SAMPFUNCS_API stInputInfo
{
    void                                    *pD3DDevice;
    void                                    *pDXUTDialog;
    class _CDXUTEditBox                        *pDXUTEditBox;
    CMDPROC                                    pCMDs[SAMP_MAX_CLIENTCMDS];
    char                                    szCMDNames[SAMP_MAX_CLIENTCMDS][33];
    int                                        iCMDCount;
    int                                        iInputEnabled;
    char                                    szInputBuffer[129];
    char                                    szRecallBufffer[10][129];
    char                                    szCurrentBuffer[129];
    int                                        iCurrentRecall;
    int                                        iTotalRecalls;
    CMDPROC                                    pszDefaultCMD;

    // functions
    void                                    AddClientCommand(char *Command, DWORD Function);
    void                                    EnableInput(void);
    void                                    DisableInput(void);
    void                                    ProcessInput();
    bool                                    UnregisterClientCommand(char *Command);
};
 
  • Влюблен
Реакции: TheLeftExit

sc6ut

неизвестный
Модератор
384
1,096
Твоё решение позволяет внутри C++ зарегать колбек из другого языка (регистрируем свой void(string), внутри дёргаем data/c_str, полученную строку передаём в C#/другой язык). Для этого нужно на каждую команду, которую я хочу зарегистрировать, писать отдельную функцию-враппер в C++ проекте. Я хочу этого избежать, т.к. иначе приходится в свой C++ проект писать такую гадость для импорта N разных команд.

C++:
#define COMMAND_NAMESPACE CommandBindings
#define DEFINE_COMMAND(entryPointName) \
    namespace COMMAND_NAMESPACE { \
        static CSharpCommandCallback entryPointName; \
        void Load##entryPointName() { entryPointName = GetCommandCallback(#entryPointName); } \
        void __stdcall On##entryPointName(std::string text) { entryPointName(text.c_str()); } \
    }
#define REGISTER_COMMAND(commandName, entryPointName) \
    COMMAND_NAMESPACE::Load##entryPointName(); \
    SF->getSAMP()->registerChatCommand(commandName, CommandBindings::On##entryPointName);

DEFINE_COMMAND(Test1);
DEFINE_COMMAND(Test2);
DEFINE_COMMAND(Test3);
static void RegisterChatCommands() {
    REGISTER_COMMAND("sfsharptest1", Test1);
    REGISTER_COMMAND("sfsharptest2", Test2);
    REGISTER_COMMAND("sfsharptest2", Test2);
}

Я хочу вместо этого единожды экспортировать в C# код одну функцию, и внутри C# регистрировать что и сколько влезет. Как-то так:

C++:
static void __stdcall RegisterChatCommand(char* commandName, void(__stdcall* commandProc)(std::string params)) {
    SF->getSAMP()->registerChatCommand(commandName, commandProc);
}

// Этот указатель улетает в C#
void(__stdcall* registerChatCommand)(char*, void(__stdcall*)(std::string params)) = RegisterChatCommand;
C#:
private static delegate* unmanaged[Stdcall]<byte*, delegate* unmanaged[Stdcall]<WHICHTYPE, void>, void> registerChatCommand;
public static void ExampleCode()
{
    ReadOnlySpan<byte> commandName = "Hello!"u8;
    fixed(byte* pCommandName = commandName)
    {
        registerChatCommand(pCommandName, &OnChatCommand);
    }
}
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
public static void OnChatCommand(WHICHTYPE text)
{
    SF.LogToChat("OnChatCommand");
}
На месте WHICHTYPE должен быть std::string, но этот класс невозможно передавать между языками как битную структуру без отстрела ноги. Если бы вместо string был char*, вместо WHICHTYPE был бы byte* и всё было бы в шоколаде.

Это всё никому кроме меня наверное не надо, но и повода тут использовать string вместо char* я тоже не вижу.
я не умею в c#, но наверное ты можешь создать тайп который в памяти выглядит как std::string и получать его. примерно как тут:

тут я это сделал потому что самп скомпилирован компайлером от майкрософт, а мой плагин gcc и имплементация std::string разная. но в теории, ты можешь что-то подобное сделать в твоем случае.
 
  • Нравится
Реакции: FYP и TheLeftExit

TheLeftExit

Участник
35
15
Можно как-то зафорсить загрузку значений score, чтобы SF->getSAMP()->getPlayers()->remotePlayerInfo[playerId]->score показывало актуальные значения а не 0?
Текущий костыль - getScoreboard()->Enable(true), ждать два фрейма mainloop, getScoreboard()->Enable(false), и ждать пока ->score не вернёт !=0 (на срп нулей не бывает, так что есть гарантия 0 = не загрузился). Но флик скорборда на 1-2 кадра мешается.
 

Musaigen

dead eyes
Проверенный
1,675
1,503
Можно как-то зафорсить загрузку значений score, чтобы SF->getSAMP()->getPlayers()->remotePlayerInfo[playerId]->score показывало актуальные значения а не 0?
Текущий костыль - getScoreboard()->Enable(true), ждать два фрейма mainloop, getScoreboard()->Enable(false), и ждать пока ->score не вернёт !=0 (на срп нулей не бывает, так что есть гарантия 0 = не загрузился). Но флик скорборда на 1-2 кадра мешается.
есть метод sendUpdateScoreAndPings();
 
  • Нравится
Реакции: TheLeftExit

Musaigen

dead eyes
Проверенный
1,675
1,503
  • Влюблен
Реакции: Ya Zaregalsya