Skip to content

Instantly share code, notes, and snippets.

@desulaid
Last active April 1, 2019 23:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save desulaid/bad3b785c789d70206ae4df7a8c988da to your computer and use it in GitHub Desktop.
Save desulaid/bad3b785c789d70206ae4df7a8c988da to your computer and use it in GitHub Desktop.
SAMP dialog plugin
#include "plugin.hpp"
/*
* Plugin functions
*/
bool Plugin::Load(void **ppData) {
pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
sampgdk::Load(ppData);
sampgdk::logprintf(" Plugin %s v%s by %s has been loaded",
plugin_name, plugin_version, plugin_author);
return true;
}
void Plugin::Unload() {
sampgdk::logprintf(" Plugin %s has been unloaded", plugin_name);
}
int Plugin::AmxLoad(AMX *amx) {
const std::vector<AMX_NATIVE_INFO> natives{
{ "DialogShowForPlayer", Native::n_DialogShowForPlayer }
};
int publ_count = 0;
amx_NumPublics(amx, &publ_count);
if (!publ_count) {
return AMX_ERR_NONE;
}
const std::regex regex_publ_name("dlg_[A-Za-z0-9]+");
for (int i = 0; i < publ_count; i++) {
std::string publ_name = Utils::GetPublName(amx, i);
std::smatch match;
if (std::regex_match(publ_name, match, regex_publ_name)) {
std::vector<plugin_dialog_t> plugin_dialog;
plugin_dialog_t dialog{ Utils::GetPublAddress(amx, i) , amx};
plugin_dialog.push_back(dialog);
public_fuinctions.insert(public_fuinctions.begin(),
std::pair<std::string, std::vector<plugin_dialog_t>>
(publ_name, plugin_dialog));
}
}
return amx_Register(amx, natives.data(), natives.size());
}
int Plugin::AmxUnload(AMX *amx) {
sampgdk::Unload();
return AMX_ERR_NONE;
}
/*
* Thanks a lot to @KashCherry
*/
namespace Utils = Plugin::Utils;
cell Utils::GetPublAddress(AMX *amx, int index) {
auto hdr = reinterpret_cast<AMX_HEADER *>(amx->base);
assert(hdr != NULL);
assert(hdr->magic == AMX_MAGIC);
auto func = reinterpret_cast<AMX_FUNCSTUB *>(
reinterpret_cast<unsigned char *>(hdr)
+ static_cast<int>(hdr->publics)
+ index * static_cast<int>(hdr->defsize));
return func->address;
}
std::string Utils::GetPublName(AMX *amx, int index) {
char name[32];
amx_GetPublic(amx, index, name);
return std::string(name);
}
int Utils::ExecutePubl(AMX *amx, cell *retval, cell address) {
auto hdr = reinterpret_cast<AMX_HEADER *>(amx->base);
assert(hdr != NULL);
assert(hdr->magic == AMX_MAGIC);
cell cip = hdr->cip;
hdr->cip = address;
int result = amx_Exec(amx, retval, AMX_EXEC_MAIN);
hdr->cip = cip;
return result;
}
/*
* Pawn native function
*/
namespace Native = Plugin::Native;
cell AMX_NATIVE_CALL Native::n_DialogShowForPlayer(AMX *amx, cell *params) {
char *name;
amx_StrParam(amx, params[2], name);
std::string publ_name = "dlg_";
publ_name += name;
public_fuinctions_t::const_iterator value = public_fuinctions.find(publ_name);
if (value == public_fuinctions.end()) {
sampgdk::logprintf("[ERROR] func %s not found", name);
return -1;
}
char *caption, *info, *button1, *button2;
amx_StrParam(amx, params[4], caption);
amx_StrParam(amx, params[5], info);
amx_StrParam(amx, params[6], button1);
amx_StrParam(amx, params[7], button2);
current_public_fuinctions.insert(current_public_fuinctions.begin(),
std::pair<int, std::string>(params[1], publ_name));
ShowPlayerDialog(params[1], inital_dialog_id, params[3],
caption, info, button1, button2);
return 1;
}
PLUGIN_EXPORT bool PLUGIN_CALL OnDialogResponse(int playerid, int dialogid,
int response, int listitem, const char *inputtext) {
if (dialogid == Plugin::inital_dialog_id) {
auto current_dialog = Plugin::current_public_fuinctions.find(playerid);
if (current_dialog == Plugin::current_public_fuinctions.end()) {
return 1;
}
auto current_function = Plugin::public_fuinctions.find(current_dialog->second);
cell addr_params, return_value;
for (size_t i = 0; i < current_function->second.size(); i++) {
amx_PushString(current_function->second[i].amx, &addr_params,
nullptr, inputtext, NULL, NULL);
amx_Push(current_function->second[i].amx, listitem);
amx_Push(current_function->second[i].amx, response);
amx_Push(current_function->second[i].amx, playerid);
Utils::ExecutePubl(current_function->second[i].amx, &return_value,
current_function->second[i].address);
amx_Release(current_function->second[i].amx, addr_params);
}
Plugin::current_public_fuinctions.erase(current_dialog);
return 1;
}
return 1;
}
#ifndef PLUGIN_HPP
#define PLUGIN_HPP
#define HAVE_STDINT_H
#include <amx\amx.h>
#include <plugincommon.h>
#define SAMPGDK_AMALGAMATION
#include <sampgdk.h>
#include <string>
#include <cassert>
#include <regex>
#include <map>
extern void *pAMXFunctions;
namespace Plugin {
constexpr const char
*plugin_name = "Daiarogu",
*plugin_author = "Anton Styazhkin",
*plugin_version = "1.0.2";
static const int
inital_dialog_id = 32767;
/*
* Addresses of all public functions in script.
*/
struct plugin_dialog_t {
cell address;
AMX *amx;
};
using public_fuinctions_t = std::map<std::string, std::vector<plugin_dialog_t>>;
public_fuinctions_t public_fuinctions;
using current_public_fuinctions_t = std::map<int, std::string>;
current_public_fuinctions_t current_public_fuinctions;
unsigned int Supports() {
return sampgdk::Supports() | SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}
bool Load(void **ppData);
void Unload();
int AmxLoad(AMX *amx);
int AmxUnload(AMX *amx);
namespace Native {
cell AMX_NATIVE_CALL n_DialogShowForPlayer(AMX *amx, cell *params);
}
namespace Utils {
cell GetPublAddress(AMX *amx, int index);
std::string GetPublName(AMX *amx, int index);
int ExecutePubl(AMX *amx, cell *retval, cell address);
}
}
PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
return Plugin::Supports();
}
PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
return Plugin::Load(ppData);
}
PLUGIN_EXPORT void PLUGIN_CALL Unload() {
Plugin::Unload();
}
PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
return Plugin::AmxLoad(amx);
}
PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
return Plugin::AmxUnload(amx);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment