[SA:MP Server Plugin] Проблема с указателем на amx

routefleeder

Известный
Автор темы
35
22
Всем ку. Вторые сутки не могу решить одну проблему с кастомным коллбеком в серверном плагине. Наверняка на бластхаке найдутся шарящие за структуру работы плагинов. Так вот, ближе к сути. Ниже покажу код функции которая должна вызывать коллбек в amx'е и то как я получаю указатель на него. Вероятно проблема как раз-таки с невалидностью указателя AMX*, у меня просто крашит сервер в момент выполнения OnPlayerPressKey. Буду премного благодарен, если кто-то сможет помочь.

Custom Amx Callback:
#include "sampgdk.h"
#include "Callbacks.h" // тут есть инклуд CGameMode.h со структурой

cell PluginCallbacks::OnPlayerPressKey(CGameMode* gamemode, int key, int playerid)
{
    if(!gamemode->m_bInitialised) return 0;

    int amx_id = 0;
    cell retval = 0; // Amx-Callback return value

    if(!amx_FindPublic(&gamemode->m_amx, "OnPlayerPressKey", &amx_id))
    {
        amx_Push(&gamemode->m_amx, key);
        amx_Push(&gamemode->m_amx, playerid);
        amx_Exec(&gamemode->m_amx, &retval, amx_id);
    }

    return retval;
}

получаем указатель и вызываем функцию:

Call callback-function:
CNetGame* netgame_ptr = PluginPointers::GetCNetGamePointer(); // я на сто процентов уверен, что получаю валидный глобальный указатель на CNetGame, потому что он прекрасно работает в других местах кода
CGameMode* gm_ptrr = netgame_ptr->m_pGameMode;
PluginCallbacks::OnPlayerPressKey(gm_ptrr, key, playerid); // параметры key и playerid так же точно валидны, ведь я вижу вывод их в консоль сервера
 
Решение
Вот пример с samp-ptl:

C++:
#include "ptl.h"

class Script : public ptl::AbstractScript<Script> {
 private:
      std::shared_ptr<ptl::Public> onTest_;

 public:
    // враппер для вызова каллбека из amx
      void OnTest(std::uint32_t playerId) {
        if (onTest_ && onTest_->Exists()) {
            onTest_->Exec(playerId);
          }
    }

      bool OnLoad() {
      int numPublics{};
      amx_->NumPublics(&numPublics);

      for (int index{}; index < numPublics; index++) {
          auto publicName = GetPublicName(index);
          if (publicName == "OnPlayerTest") {
              onTest_ = MakePublic(publicName, false);
          }
      }

      return true;
    }
};

// Также нужна реализация ptl::AbstractPlugin с вашей...

routefleeder

Известный
Автор темы
35
22
Использовал когда-нибудь samp-ptl?
Никаких указателей не надо, сделано всё за тебя :)
Ну я sampgdk юзаю, там всё как в samp-ptl, да и с samp-ptl оригинальным тоже игрался. В общем я принял решение хукать OnGameModeInit и OnFilterscriptInit для получения валидного указателя
 

вайега52

Налуашил состояние
Модератор
2,943
3,001
Вот пример с samp-ptl:

C++:
#include "ptl.h"

class Script : public ptl::AbstractScript<Script> {
 private:
      std::shared_ptr<ptl::Public> onTest_;

 public:
    // враппер для вызова каллбека из amx
      void OnTest(std::uint32_t playerId) {
        if (onTest_ && onTest_->Exists()) {
            onTest_->Exec(playerId);
          }
    }

      bool OnLoad() {
      int numPublics{};
      amx_->NumPublics(&numPublics);

      for (int index{}; index < numPublics; index++) {
          auto publicName = GetPublicName(index);
          if (publicName == "OnPlayerTest") {
              onTest_ = MakePublic(publicName, false);
          }
      }

      return true;
    }
};

// Также нужна реализация ptl::AbstractPlugin с вашей имплементацией плагина и скрипта
class Plugin : public ptl::AbstractPlugin<Plugin, Script> {
 private:
 public:
  const char *Name();

  bool OnLoad();
};

// А также вызовы:
PLUGIN_EXPORT void PLUGIN_CALL AmxLoad(AMX *amx) { Plugin::DoAmxLoad(amx); }

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
  return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}