Введение в скриптинг: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
No edit summary
Line 1: Line 1:
Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip архив, содержащий набор файлов, а также мета файл, описывающий серверу, как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, а также могут быть запущены несколько ресурсов одновременно. Всё, что выполняется с помощью сценариев находится в ресурсах, что реализовано в сценариях: игровые режимы, игровые карты или что-либо ещё - все это ресурсы.
Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip архив, содержащий набор файлов, а также мета файл, описывающий серверу, как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, а также могут быть запущены несколько ресурсов одновременно. Всё, что выполняется с помощью сценариев находится в ресурсах, что реализовано в сценариях: игровые режимы, игровые карты или что-либо ещё - все это ресурсы.


'''Вам будет проще начать писать сценарии на языке Lua, если вы будете использовать специализированный Lua-редактор такой как[http://notepad-plus.sourceforge.net/uk/site.htm Notepad++] или [http://luaedit.luaforge.net/ LuaEdit].'''
'''Вам будет проще начать писать сценарии на языке Lua, если вы будете использовать специализированный Lua-редактор такой как [http://notepad-plus.sourceforge.net/uk/site.htm Notepad++] или [http://luaedit.luaforge.net/ LuaEdit]. Для дистрибутивов GNU/Linux возможно использовать встроенный по умолчанию (в большую часть ОС) Gedit'''  


==Создание простого сценария==
==Создание простого сценария==

Revision as of 18:45, 30 January 2012

Ресурсы являются ключевой частью MTA. Ресурс - это папка или zip архив, содержащий набор файлов, а также мета файл, описывающий серверу, как нужно загружать ресурс и из каких файлов он состоит. Ресурс играет практически ту же роль, что и программа в операционной системе - он может быть запущен и остановлен, а также могут быть запущены несколько ресурсов одновременно. Всё, что выполняется с помощью сценариев находится в ресурсах, что реализовано в сценариях: игровые режимы, игровые карты или что-либо ещё - все это ресурсы.

Вам будет проще начать писать сценарии на языке Lua, если вы будете использовать специализированный Lua-редактор такой как Notepad++ или LuaEdit. Для дистрибутивов GNU/Linux возможно использовать встроенный по умолчанию (в большую часть ОС) Gedit

Создание простого сценария

Для начала давайте сделаем так, чтобы по команде игрока "createvehicle" рядом с игроком создавалась машина.

Подготовка

Как описывалось выше, ресурс является папкой или zip архивом, поэтому для начала мы должны создать папку. Название папки является названием ресурса. Это название используется для запуска или прекращения выполнения ресурса и для обращения к ресурсу в сценариях. В нашем примере, папку необходимо назвать commands.

Каждому ресурсу необходим файл meta.xml. В нашем случае, мы хотим создать сценарий, который обеспечит пользователю выполнение нескольких простых команд, поэтому нам необходимо сообщить серверу о необходимости загрузки файла сценария, в нашем случае таким файлом сценария пусть будет script.lua. Содержимое файла meta.xml:

<meta>
  <info author="YourName" description="A few simple commands" />
  <script src="script.lua" />
 </meta>

Теперь нам необходимо создать файл script.lua, о котором упоминалось выше, в той же самой директории, где расположен файл meta.xml. В результате содержимое папки commands должно быть таким:

/commands/meta.xml
/commands/script.lua

Написание сценария

Начнем с содержимого файла script.lua. Как описывалось выше, нам необходимо обеспечить команду, которая будет создавать машину рядом с игроком. Для начала нам необходимо создать функцию, которую мы будем вызывать, и обработчик команды, который позволит игроку вводить и выполнять команду в окне консоли.

-- создание функции, вызываемой обработчиком команды, с аргументами: thePlayer, command, vehicleModel
function createVehicleForPlayer(thePlayer, command, vehicleModel)
   -- код сценария для создания машины
end

-- создание обработчика команды
addCommandHandler("createvehicle", createVehicleForPlayer)

Обратите внимание: Имена функций в коде примеров являются ссылками на wiki-статьи, описывающие функции в документации.

О обработчиках команд

Первым аргументом addCommandHandler название команды, введенной игроком, второй аргумент - функция, которая будет вызвана, в нашем случае это createVehicleForPlayer.

Если вы уже знакомы с написанием сценариев, то вам наверняка приходилось вызывать функции следующего вида:

functionName(argument1, argument2, argument3, ..)

Таким способом мы вызываем функцию addCommandHandler, а затем функцию createVehicleForPlayer. Она, конечно же, может быть вызвана этим же способом отдельно. Но для нее мы используем обработчик команды, который вызывает ее в пожожей манере, но только внутри.

Например: Какой-нибудь игрок в процессе игры введет в окно консоли команду "createvehicle 468" для создания машины Sanchez, обработчик команды вызовет функцию createVehicleForPlayer , так же, как если бы у нас в коде сценария была строка:

createVehiceForPlayer(thePlayer,"createvehicle","468") -- thePlayer это игрок, который ввел команду

Эта функция имеет несколько параметров: параметр, отвечающий за игрока, который ввел команду, параметр, имеющий в качестве значения введенную команду и параметр, содержащий текст, который следовал после команды, в нашем случае это "468" - идентификатор машины Sanchez. Первые два параметра такие же, как и у остальных обработчиков команд, о которых вы можете прочитать информацию на странице addEventHandler. Поэтому, вы всегда должны определить, по крайней мере, эти два параметра для использования чего-либо после них (например, для обработки текста, введенного после команды, как в нашем примере - идентификатора модели машины).

Обратите внимание: Вы можете добавить обработчик команды только ПОСЛЕ того, как вы определили функцию обработчика, иначе она не будет найдена. Порядок размещения функций имеет значение.

Написание функции

Для того, чтобы написать код созданной функции, нам необходимо продумать детали того, что мы хотим сделать:

  • Получить позицию игроков для того, чтобы знать куда поместить новую машину (допустим, что мы хотим, чтобы она появилась справа от игрока)
  • Вычислить позицию того места, куда необходимо поместить машину (это необходимо для того, чтобы она не появилась на месте игрока)
  • Создать машину
  • Проверить успешность создания машины или вывести сообщение

Для того, чтобы выполнить поставленные задачи, мы должны использовать несколько функций. Чтобы найти подходящую для решения задачи функцию, мы должны посмотреть страницу Список функций серверного приложения. Сначала нам необходима функция для получения позиции игроков. Так как игроки относятся к элементам (основным классам, описывающим игровые сущности или, проще говоря, игровые объекты), то мы сначала переходим к странице Element functions, где и находим функцию getElementPosition. Щелкнув по названию функции в списке, мы получаем описание функции. Тут же мы можем посмотреть синтаксис, возвращаемое значение и даже пример ее использования. Синтаксис показывает нам, какие аргументы необходимо передать функции.

функция getElementPosition, имеет следующий синтаксис:

float, float, float getElementPosition ( element theElement )

Три float перед названием функции - это тип возвращаемого значения. В этом случае, подобное означает, что функция возвращает три числа с плавающей точкой. В круглых скобках, вы можете увидеть аргументы, которые необходимо передать функции. В нашем случае имеется только аргумент типа element, содержащий объект, чью позицию мы хотим получить (в нашем примере это игрок).

function createVehicleForPlayer(thePlayer, command, vehicleModel)
    -- получить позицию и поместить ее в переменные x,y,z
    -- (local обозначает локальный контекст: переменные существуют только в текущей области действия. В данном случае - в пределах текущей функции)
    local x,y,z = getElementPosition(thePlayer)
end

Далее мы хотим гарантировать то, что машина не создастся прямо на игроке, поэтому мы добавляем небольшое значение переменной x, что дает на возможность создать машину правее от игрока.

function createVehicleForPlayer(thePlayer, command, vehicleModel)
    local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
    x = x + 5 -- добавить 5 единиц к позиции по оси x
end

Теперь нам необходима другая функция, а именно функция для создания машины. Мы снова начинаем ее поиск в списке функций серверного приложения, в этот раз - так как речь идет о машинах - то ищем функцию в разделе Vehicle functions, в котором мы выбираем createVehicle. В синтаксисе этой функции, нам необходимо только возвращаемое значение (которое является единственным), типа vehicle, относящееся к element. Это возвращаемое значение указывает на машину, которая только что создана. Также, вы вероятно обратили внимание на то, что некоторые аргументы заключены в квадратные скобки [ ], которые означают, что этот аргумент функции необязателен.

Теперь у нас имеются все аргументы, необходимые для выполнения команды createVehicle внутри нашей функции: мы вычислили позицию по переменным x,y,z и знаем идентификатор модели, которую мы хотим создать с помощью команды ("createvehicle 468") и мы имеем доступ к функции через переменную vehicleModel.

function createVehicleForPlayer(thePlayer, command, vehicleModel)
    local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
    x = x + 5 -- добавить 5 единиц измерения к координате x позиции игрока
    -- создать машину и сохранить возвращенный элемент vehicle в переменной ''createdVehicle''
    local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
end

Конечно, этот код может быть улучшен многими способами. По крайней мере, нам необходимо добавить проверку на успешное создание машины. На странице createVehicle мы можем прочитать в разделе Returns о том, что функция возвращает false в том случае, если неполучилось создать машину. Поэтому, нам достаточно проверить значение переменной createVehicle.

Теперь у нас имеется полность завершенный сценарий:

function createVehicleForPlayer(thePlayer, command, vehicleModel)
    local x,y,z = getElementPosition(thePlayer) -- получить позицию игрока
    x = x + 5 -- добавить 5 единиц измерения к координате x позиции игрока
    local createdVehicle = createVehicle(tonumber(vehicleModel),x,y,z)
    -- проверка на возврат значения ''false''
    if (createdVehicle == false) then
        -- если возвращено ''false'', то необходимо вывести сообщение пользователю в окно чата, но только тому игроку, который создавал машину.
        outputChatBox("Failed to create vehicle.",thePlayer)
    end
end
addCommandHandler("createvehicle", createVehicleForPlayer)

Как вы можете увидеть, в последнем примере кода появилась еще одна функция outputChatBox. О ней вы можете самостоятельно узнать, посмотрев соответствующую страницу с документацией по этой функции.

Что вы узнали

Теперь вам уже немного известны файлы ресурсов, обработчики команд и принципы поиска функций в документации, но необходимо знать больше. Следующий раздел проведет краткий обзор по некоторым ресурсам, сопровождая при необходимости изложение материала ссылками на соответствующие страницы.

Сценарии клиентской и серверной стороны

Вы возможно уже видели эти или похожие термины (сервер/клиент) на этом wiki-сайте. MTA поддерживает не только сценарии, выполняющиеся на сервере и обеспечивающие выполнение команд(похожих на ту, что была описаны выше) и другие возможности, но и также сценарии, выполняющиеся клиентским приложением MTA, которое игроки используют для соединения с игровым сервером. Причиной этому является тот факт, что некоторые возможности MTA обеспечиваются приложением клиентской стороны (например, графический пользовательский интерфейс). Другие возможности MTA работают лучше на стороне сервера или принципиально не могут быть реализованы на клиентской стороне и поэтому выполняются на стороне сервера.

Многие сценарии, которые вы будете писать (игровые режимы, карты) вероятно будут выполняться на стороне сервера, подобно тому, который был написан выше. Если вам необходимо выполнить что-либо, что нельзя выполнить на стороне сервера, вы вероятно сможете это выполнить на стороне клиента. Например, для сценария клиентской стороны, вы должны создать обычный файл сценария (например, с названием client.lua) и определить его в файле meta.xml, следующим образом:

<script src="client.lua" type="client" />

Атрибут type по умолчанию имеет значение 'server', поэтому вам необходимо определять его значение для сценариев клиентской стороны. После того, как вы выполнили это, сценарий клиентской стороны будет скачиваться на компьютер игрока при его соединении с сервером. Об этом вы можете также прочитать в статье Сценарии клиентской стороны.

Более сложные ресурсы

Предыдущий раздел кратко показал, как надо добавлять сценарии клиентской стороны в ресурсы, но на самом деле все обстоит немного сложнее. Как упоминалось в самом начале этой страницы, ресурсы могут быть чем угодно. Их цель - определить то, для чего они нужны. Далее приведены наиболее часто используемые ресурсы. Рассмотрим их содержимое, содержимое файла meta.xml и то, для чего они предназначены:

Пример 1: Вспомогательный сценарий

/admin_commands
    /meta.xml
    /commands.lua
    /client.lua
<meta>
    <info author="Someguy" description="admin commands" />
    <script src="commands.lua" />
    <script src="client.lua" type="client" />
</meta>
  • Файл commands.lua обеспечивает выполнение некоторых команд администратора, например, назначение наказаний провинившимся игрокам, или что-либо другое, что может быть полезным для администрирования сервера
  • Файл client.lua обеспечивает графический пользовательский интерфейс для легкого выполнения описанных действий

Этот пример ресурса может быть в состоянии выполнения всё время (даже может запускаться автоматически при начале работы сервера), так как он может использоваться в течении всего игрового процесса и изменять игровой процесс, в случае если администратор решит выполнить какое-либо действие.

Пример 2: Игровой режим

/counterstrike
    /meta.xml
    /counterstrike.lua
    /buymenu.lua
<meta>
    <info author="Someguy" description="Counterstrike remake" type="gamemode" />
    <script src="counterstrike.lua" />
    <script src="buymenu.lua" type="client" />
</meta>
  • Файл counterstrike.lua содержит следующие возможности:
    • Позволяет игрокам выбирать команду, за которую они хотят играть и присоединяться к команде
    • Обеспечивает игрокам возможность выбора оружия, цели игры и команды (информация подобного характера может также содержаться в файле игровой карты - об этом будет сказано ниже)
    • Определяет правила игры,например, момент наступления конца раунда, какие действия должны произойти после гибели персонажа игрока.
    • .. и возможно что-либо ещё
  • Файл buymenu.lua - сценарий клиентской стороны для создания меню покупки оружия.

Этот пример может быть отнесен к игровому режиму потому как он не только связан с процессом игры, но и фактически определяет правила игры. Атрибут type показывает, что этот пример работает в Map manager, хотя и существует другой ресурс, написанный QA Team для управления игровыми режимами и загрузки игровых карт. Его рекомендуется использовать, потому как ваш игровой решим будет основан на принципах, поддерживаемых им.

Это также означает, что игровой режим вероятно не сможет быть запущен без игровой карты. Игровые режимы должны всегда стремиться настолько использовать общие принципы, насколько это возможно. Далее приведен пример игровой карты.

Пример 3: Игровая карта

/cs-airport
    /meta.xml
    /airport.map
    /airport.lua
<meta>
    <info author="Someguy" description="Counterstrike airport map" type="map" gamemodes="counterstrike" />
    <map src="airport.map" />
    <script src="airport.lua" />
</meta>
  • Файл airport.map в XML файле, обеспечивает информацию о игровой карте игровому режиму, которая может включать:
    • Места, где на карте должны появляться игроки, с каким оружием, какие команды имеются
    • Какие цели имеются
    • Погода, время, ограничение времени
    • Возможные машины
  • файл airport.lua может содержать возможности характерные для конкретной игровой карты, которые в свою очередь могуть включать:
    • Реализацию действий, которые могут произойти после открытия двери, ворот и т.п., взрыва чего-либо.
    • Создание и перемещение некоторых игровых объектов, или управление объектами, создаваемыми в файле .map
    • .. что-либо ещё, что может относиться к конкретной карте

Как вы можете увидеть, значение атрибута type изменено на 'map', это говорит Map manager о том, что этот ресурс является игровой картой, а атрибут gamemodes говорит о том, к каким игровым режимам относится эта игровая карта. В примере игровая карта относится к игровому режиму, описанному в примере выше. Для ресурса "игровая карта" может быть написан отдельный сценарий. Конечно, это не является необходимым для всех игровых карт, но в то же время открывает создателям игровых карт широкие возможности для создания своих собственных правил игры в игровом режиме, для которого они создают карту.

Файл airport.map может иметь следующий вид:

<map mode="deathmatch" version="1.0">
    <terrorists>
        <spawnpoint posX="2332.23" posY="-12232.33" posZ="4.42223" skins="23-40" />
    </terrorists>
    <counterterrorists>
        <spawnpoint posX="2334.23443" posY="-12300.233" posZ="10.2344" skins="40-50" />
    </counterterrorists>

    <bomb posX="23342.23" posY="" posZ="" />
    
    <vehicle posX="" posY="" posZ="" model="602" />    
    <vehicle posX="" posY="" posZ="" model="603" />    
</map>

Когда игровой режим запущен с игровой картой, mapmanager автоматически запускает ресурсы игровой карты и информация, которую они содержат может быть считана ресурсом игрового режима. При изменении игровой карты, выполнение ресурса текущей игровой карты останавливается и запускается выполнение ресурса следующей игровой карты.

События

События являются механизмом MTA сообщать сценариям о том, что произошло. Например, при смерти персонажа игрока, срабатывает событие onPlayerWasted. В нем выполняются какие-либо действия, которые необходимо выполнить при смерти персонажа игрока, вы можете подготовить что-то подобное для добавления обработчика команды, как показано в разделе "Написание сценария".

В этом примере выводится сообщение, содержащее имя игрока, персонаж которого погиб:

function playerDied(totalAmmo, killer, killerWeapon, bodypart)
    outputChatBox(getPlayerName(source).." died!")
end
addEventHandler("onPlayerWasted",getRootElement(),playerDied)

Вместо отображения необходимых параметров, на страницах документации, посвященных событиям, показано какие параметры передаются в функцию-обработчик, подобно тому как сделано в обработчике команды, только с тем отличием, что используется не команда, а событие. Другим немаловажным аспектом является переменная source, которая имеется в обработчике функций. Она не добавляется в список параметров функции, но тем не менее используется. Она принимает различные значения в зависимости от события. Для событий, относящихся к игроку (как в в примере выше) она принимает значение типа player, которое относится к элементам (element).

Заключение

Теперь вы знаете основные аспекты, использующиеся при написании сценариев в MTA, а также ознакомились с частью документации. Главная страница содержит ссылки на более подробную информацию, учебники и справочники, которые при желании позволят вам более глубже узнать многие вещи о MTA.