Last active
April 1, 2019 23:04
-
-
Save desulaid/bad3b785c789d70206ae4df7a8c988da to your computer and use it in GitHub Desktop.
SAMP dialog plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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