I. Предисловие
- В этой статье я не буду учить кого-либо С++, как во многих статьях о написании плагинов на pawn. Я лишь расскажу принцип работы плагинов, использование metaAPI и функций.
- Если вы думаете, что метамод откроет Вам доступ напрямую ко всему движку - очень ошибаетесь. Единственным существенным(!) отличием amxx-плагинов от meta-плагинов - использование С++ вместо pawn.
II. Теория
Я уверен, что почти 99.9% администраторов даже понятия не имеют о том, для чего же именно предназначен metamod. Metamod - управляющий плагинами(dll). В оригинале:
Metamod is a plugin/DLL manager that sits between the Half-Life Engine and an HL Game mod, allowing the dynamic loading/unloading of mod-like DLL plugins to add functionality to the HL server or game mod.
Но Вы можете подключать плагин напрямую к движку, т.е. так же, как подключается metamod.
Основной принцип работы метамода таков:
- Загрузка плагинов начинается как только движок вызовет функцию GiveFnptrsToDll (расшифровать можно как получение_указателей_функций)
- Из конфига метамода выбираются все необходимые плагины(незакомментированнные и соответствующие платформе).
- Каждый плагин обрабатывается (открывается dll, выполняется поиск необходимых функций) и вызывается ряд функций:
Meta_Init(если существует)
GiveFnptrsToDll
Meta_Query
Meta_Attach - Если существуют какие-либо другие функции получения таблиц функций, то и они вызываются:
GetEntityAPI
GetEntityAPI_Post
GetEntityAPI2
GetEntityAPI2_Post
GetNewDLLFunctions
GetNewDLLFunctions_Post
GetEngineFunctions
GetEngineFunctions_Post
Для каждого вызова функции(ориг. api call) из движка\длл мода выполняются стандартные операции:
- для каждого плагина, который "захватывает" вызов данной функции, вызывается соответствующая функция внутри плагина
- вызывается оригинальная функция из движка\длл мода
- для каждого плагина проверяется наличие "post" функции, которая, если существует, вызывается после оригинальной
Любой плагин может заменить оригинальную функцию двумя способами:
- запретить вызов оригинальной функции(SUPERCEDE)
- заменить возвращаемое значение оригинальной функции(OVERRIDE)
После вызова всех функций из плагинов, проверяется META_RESULT и выполняется необходимое действие. Замечу, что supercede/override влияет только на оригинальную функцию; функции других плагинов все равно будут вызваны.
Но плагин может сообщить результат выполнения своей функции последующим плагинам, используя дополнительные возвращаемые значения(metamod их не использует - только остальные плагины):
- я тут приложил свою руку(HANDLED)
- я тут ничего такого не сделал(IGNORED)
Рассмотрим эти значения подробнее. Возможные значения META_RESULT, которые может вернуть функция плагина:
- MRES_IGNORED
Тут плагин ничего не делал. Обычно используется для сообщения ТОЛЬКО другим плагинам, что в данном случае плагин остается в стороне - он не перехватывал событие. Если значение не будет заменено другим плагином - в конце концов вызовется оригинальная функция. Это справедливо для любых функций, как обычных, так и "post". - MRES_HANDLED
Плагин перехватил ситуацию или сделал что-либо с информацией. Опять-таки, обычно используется для сообщения ТОЛЬКО другим плагинам, что мы тут обо всем позаботимся. Если значение не будет заменено другим плагином - в конце концов вызовется оригинальная функция. Это справедливо для любых функций, как обычных, так и "post". - MRES_OVERRIDE
Плагин предоставляет своё возвращаемое значение для оригинальной функции, которое должно использоваться вместо возвращаемого значения из игровой DLL(плагин заменяет (ориг. "overrides") возвращаемое значение игровой DLL). Если значение не будет заменено другим плагином - в конце концов вызовется оригинальная функция. Это справедливо для любых функций, как обычных, так и "post". - MRES_SUPERCEDE
Плагин выполнил нужные действия для данной функции и вызов оригинальной функции больше не нужен(плагин "переписал" (ориг. "supercedes") оригинальную функцию). Это справедливо только для обычных функций, т.к. post функции не способны остановить вызов оригинальной функции - ведь она уже была вызвана. также необходимо помнить, что это не остановит вызов функций в других плагинах - действие применимо только к оригинальной функции из игровой DLL. Any return value for the routine should be specified as well by the plugin.
После вызова всех функций из плагинов, текущее значение META_RESULT задается наивысшим по приоритету среди значений, которые вернули плагины. После чего проверяется необходимость вызова оригинальной функции. В зависимости от результата, вызывается или пропускается(плагин вернул META_SUPERCEDE) оригинальная функция из игровой DLL. Все "post" функции вызываются точно так же(если META_SUPERCEDE не является текущим значение META_RESULT).
Если какой-либо из плагинов установил значение META_OVERRIDE или META_SUPERCEDE, то значение, которое вернул последний плагин будет возвращено движку оригинальной функцией(для не-void функций). Поэтому расположение плагинов в metamod.ini может влиять на конечный результат.
Макросы, используемые для работы с возвращаемым значением:
- SET_META_RESULT(результат)
Устанавливает META_RESULT для данного плагина. - RETURN_META(результат)
Устанавливает META_RESULT для данного плагина и возвращает результат. Используется в "void" функциях. - RETURN_META_VALUE(результат, значение)
Устанавливает META_RESULT для данного плагина и возвращает указанное значение. Используется в не-"void" функциях, тип возвращаемого значения ни на что не влияет. - META_RESULT_STATUS
Получает текущее значение META_RESULT для данной функции из плагинов. Вернет наивысший по приоритету результат(по возрастающей: IGNORED, HANDLED, OVERRIDE, SUPERCEDE). - META_RESULT_PREVIOUS
Получает значение META_RESULT от предыдущего плагина. - META_RESULT_ORIG_RET(тип)
Получает оригинальное возвращаемое значение оригинальной функции, например возвращаемое значение функции из игровой DLL. Тип возвращаемого значения оригинальной функции должен быть указан в макросе; используется для приведения типов в выражении. Это справедливо только для "post" функций. - META_RESULT_OVERRIDE_RET(тип)
Получает возвращаемое значение из плагина, который вернул META_OVERRIDE или META_SUPERCEDE. Тип возвращаемого значения оригинальной функции должен быть указан в макросе; используется для приведения типов в выражении. Должен использоваться только после проверки META_RESULT если существует доступное значение для замены возвращаемого значения оригинальной функции. - MDLL_*(аргументы)
Вызывает указанную DLLAPI функцию в игровой DLL. Например, MDLL_GameDLLInit(аргументы), MDLL_Spawn(аргументы), и т.д. - MNEW_*(аргументы)
Вызывает указанную NEWAPI функцию в игровой DLL. Например, MNEW_GameShutdown(аргументы), и т.д.
III. HelloWorld
Я знаю, что вам уже не терпится. Вот минимум кода, который потребуется для компиляции плагина под Windows. Linux все-таки требуется отдельной статьи.
- Код: Выделить всё
#include <extdll.h>
#include <meta_api.h>
plugin_info_t info = {
META_INTERFACE_VERSION, // ifvers
"HELLO WORLD", // name
"1.01", // version
"2011/01/15", // date
"--===((((][@KIRjkeeee))))===--", // author
"http://ultra.ucoz.ru", // url
"HELLOWORLD", // logtag, all caps please
PT_ANYTIME, // (when) loadable
PT_ANYPAUSE // (when) unloadable
};
enginefuncs_t g_engfuncs;
void WINAPI GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t));
}
C_DLLEXPORT int Meta_Query(char *interfaceVersion, plugin_info_t **pinfo, mutil_funcs_t *pMetaUtilFuncs)
{
*pinfo = &info;
ALERT(at_console, "[HELLOWORLD]: meta_query\n");
return(TRUE);
}
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
{
ALERT(at_console, "[HELLOWORLD]: meta_attach\n");
return(TRUE);
}
C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{
ALERT(at_console, "[HELLOWORLD]: meta_detach\n");
return(TRUE);
}
Для компиляции в Visual Studio вам понадобится:
- METASDK 1.19(папка metamod в исходниках метамода)
- HLSDK 2.3 p3
В параметры проекта, в качестве дополнительных include-директорий добавить следующие пути:
- %hlsdk%/common
- %hlsdk%/dlls
- %hlsdk%/engine
- %hlsdk%/pm_shared
- %metasrc%/metamod
В настройках проекта замените параметр Runtime Library на Multi-Treaded (параметр /MD на /MT в командной строке компилятора). Шаг необязательный, заменяет тип линковки VC библиотек, а именно - вам будут не нужны отдельные библиотеки, т.к. они будут "вшиты" в программу.
Запустите компиляцию проекта(клавиша F7 или Build->Build Solution) и добавьте плагин в metamod.ini. При запуске сервера вы увидите в консоли сообщения от нашего плагина:
[HELLOWORLD]: meta_query
[HELLOWORLD]: meta_attach
А при выгрузке плагина(в консоли сервера - unload x, где x - номер плагина) увидите следующее сообщение:
[HELLOWORLD]: meta_detach
В статье использован материал с сайта metamod.org.
В следующей главе будет рассмотрена тема использования таблиц функций, практическое применение информации из этой статьи. Просьба тут оставлять комментарии и вопросы ТОЛЬКО к статье, а все вопросы по кодингу в соответствующем разделе.
tags/тэги: metamod, кодинг, плагины, как начать, создание, написание