Русское сообщество по скриптингу

Вперед в прошлое [Глава I]

Статьи или фрагменты кода для новичков и уже опытных скриптеров по Metamod.
Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только обучающему материалу по Metamod.

Вперед в прошлое [Глава I]

Сообщение 6a6kin » 26 янв 2011, 19:10

Автор: 6a6kin

I. Предисловие
  1. В этой статье я не буду учить кого-либо С++, как во многих статьях о написании плагинов на pawn. Я лишь расскажу принцип работы плагинов, использование metaAPI и функций.
  2. Если вы думаете, что метамод откроет Вам доступ напрямую ко всему движку - очень ошибаетесь. Единственным существенным(!) отличием 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.

Основной принцип работы метамода таков:
[spoiler]
  1. Загрузка плагинов начинается как только движок вызовет функцию GiveFnptrsToDll (расшифровать можно как получение_указателей_функций)
  2. Из конфига метамода выбираются все необходимые плагины(незакомментированнные и соответствующие платформе).
  3. Каждый плагин обрабатывается (открывается dll, выполняется поиск необходимых функций) и вызывается ряд функций:
    Meta_Init(если существует)
    GiveFnptrsToDll
    Meta_Query
    Meta_Attach
  4. Если существуют какие-либо другие функции получения таблиц функций, то и они вызываются:
    GetEntityAPI
    GetEntityAPI_Post
    GetEntityAPI2
    GetEntityAPI2_Post

    GetNewDLLFunctions
    GetNewDLLFunctions_Post

    GetEngineFunctions
    GetEngineFunctions_Post
[/spoiler]
Для каждого вызова функции(ориг. api call) из движка\длл мода выполняются стандартные операции:
  • для каждого плагина, который "захватывает" вызов данной функции, вызывается соответствующая функция внутри плагина
  • вызывается оригинальная функция из движка\длл мода
  • для каждого плагина проверяется наличие "post" функции, которая, если существует, вызывается после оригинальной

Любой плагин может заменить оригинальную функцию двумя способами:
  • запретить вызов оригинальной функции(SUPERCEDE)
  • заменить возвращаемое значение оригинальной функции(OVERRIDE)

После вызова всех функций из плагинов, проверяется META_RESULT и выполняется необходимое действие. Замечу, что supercede/override влияет только на оригинальную функцию; функции других плагинов все равно будут вызваны.
Но плагин может сообщить результат выполнения своей функции последующим плагинам, используя дополнительные возвращаемые значения(metamod их не использует - только остальные плагины):
[spoiler]
  • я тут приложил свою руку(HANDLED)
  • я тут ничего такого не сделал(IGNORED)
Необходимо помнить, что каждая функция ОБЯЗАНА вернуть META_RESULT. В случае отсутствия установленного META_RESULT, в логах появятся предупреждающие ошибки.

Рассмотрим эти значения подробнее. Возможные значения 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.
[/spoiler]
После вызова всех функций из плагинов, текущее значение META_RESULT задается наивысшим по приоритету среди значений, которые вернули плагины. После чего проверяется необходимость вызова оригинальной функции. В зависимости от результата, вызывается или пропускается(плагин вернул META_SUPERCEDE) оригинальная функция из игровой DLL. Все "post" функции вызываются точно так же(если META_SUPERCEDE не является текущим значение META_RESULT).

Если какой-либо из плагинов установил значение META_OVERRIDE или META_SUPERCEDE, то значение, которое вернул последний плагин будет возвращено движку оригинальной функцией(для не-void функций). Поэтому расположение плагинов в metamod.ini может влиять на конечный результат.

Макросы, используемые для работы с возвращаемым значением:
[spoiler]
  • 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(аргументы), и т.д.
[/spoiler]

III. HelloWorld
Я знаю, что вам уже не терпится. Вот минимум кода, который потребуется для компиляции плагина под Windows. Linux все-таки требуется отдельной статьи.
[spoiler]
Код: Выделить всё
#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);
}
[/spoiler]
Для компиляции в 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, кодинг, плагины, как начать, создание, написание
Последний раз редактировалось 6a6kin 16 мар 2011, 20:50, всего редактировалось 2 раз(а).
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 334
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 37 раз.
Поблагодарили: 269 раз.

Re: Вперед в прошлое [Глава I]

Сообщение Slavvkko » 26 янв 2011, 21:05

Единственным существенным(!) отличием amxx-плагинов от meta-плагинов - использование С++ вместо pawn.

Что в общем то и дает «кучу возможностей».
Аватара пользователя
Slavvkko
 
Сообщения: 174
Зарегистрирован: 03 окт 2009, 17:58
Откуда: UA
Благодарил (а): 20 раз.
Поблагодарили: 55 раз.
Опыт программирования: Около года
Языки программирования: Counter-Strike 1.6

Re: Вперед в прошлое [Глава I]

Сообщение Fedcomp » 28 янв 2011, 07:01

И патчить память например, в стиле дпрото.
Не помогаю в ЛС - есть форум.
Плагины тоже не пишу, на форуме достаточно хороших скриптеров.
Аватара пользователя
Fedcomp
Администратор
 
Сообщения: 4317
Зарегистрирован: 28 авг 2009, 20:47
Благодарил (а): 694 раз.
Поблагодарили: 1178 раз.
Языки программирования: Counter-Strike 1.6

Re: Вперед в прошлое [Глава I]

Сообщение DJ_WEST » 28 янв 2011, 12:36

Респектую, хоть кто-то еще помогает со статьями ;)
Не пишите мне в ЛС: если вам нужна помощь на бесплатной основе. Любые вопросы на форум.
Аватара пользователя
DJ_WEST
Администратор
 
Сообщения: 3747
Зарегистрирован: 22 авг 2009, 00:38
Благодарил (а): 48 раз.
Поблагодарили: 2160 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Counter-Strike: Source
Left 4 Dead
Left 4 Dead 2

Re: Вперед в прошлое [Глава I]

Сообщение Slavvkko » 11 фев 2011, 23:27

Так что, продолжение будет?
Аватара пользователя
Slavvkko
 
Сообщения: 174
Зарегистрирован: 03 окт 2009, 17:58
Откуда: UA
Благодарил (а): 20 раз.
Поблагодарили: 55 раз.
Опыт программирования: Около года
Языки программирования: Counter-Strike 1.6

Re: Вперед в прошлое [Глава I]

Сообщение 6a6kin » 12 фев 2011, 02:29

Да, начал готовить почти сразу, но отложил, т.к. был занят. Надеюсь, что за эти выходные сделаю.
На заказ не пишу.
Аватара пользователя
6a6kin
Скриптер
 
Сообщения: 334
Зарегистрирован: 09 мар 2010, 16:40
Благодарил (а): 37 раз.
Поблагодарили: 269 раз.


Вернуться в Статьи / фрагменты кода

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1