Creating-your-first-script-javascript

From FiveM Wikipedia

Создание первого скрипта на JavaScript

Начало работы со сценариями для FiveM может быть немного ошеломляющим, учитывая широкий спектр возможностей и слабо распространенную документацию. В этом кратком и простом руководстве мы постараемся показать вам, как начать работу с быстрым ресурсом на JavaScript.

Необходимые условия

Прежде чем создать свой первый скрипт с помощью JavaScript, есть несколько вещей, которые вам нужно настроить и понять.

  • Общие сведения о среде выполнения JavaScript
  • Общие сведения о ресурсах и файлах манифестов

Мы будем использовать Visual Studio Code, то есть VSCode, популярный редактор кода от Microsoft. Тем не менее, вы можете использовать любой редактор кода, который вы хотите.

Ресурсы

Ресурс — это, проще говоря, набор файлов, которые можно запускать, останавливать и перезапускать по отдельности. Ваша папка server-data (при условии, что вы уже установили сервер) должна уже иметь папку с несколькими ресурсами в них.resources

Если вы работаете на своих собственных ресурсах, вы, вероятно, захотите создать каталог - этот будет проигнорирован Git при обновлении корня сервера-данных. Там мы сделаем папку, так как мы создаем, ну, тип игры с помощью системы.resources/[local]resources/[local]/mymodemapmanager

Это означает, что к настоящему времени вам понадобится папка, подобная этой, предполагая систему разработки Windows: . С этого момента мы будем вызывать эту папку.C:\your\path\to\cfx-server-data\resources\[local]\mymodemymode

Файлы манифеста

Папка ресурсов (вы знаете, это вы сделали выше) будет нуждаться в манифесте, который будет обнаружен FiveM. Поскольку это тип игры, ему также понадобится некоторая дополнительная информация, чтобы рассказать о том, что это тип игры.mymodemapmanager

Создайте файл с именем (это всегда Lua, даже если вы будете писать JS-скрипт) в своей папке. В него поместите следующий текст с помощью любимого текстового редактора:fxmanifest.luamymode

fx_version 'cerulean'
game 'gta5'

author 'An awesome dude'
description 'An awesome, but short, description'
version '1.0.0'

resource_type 'gametype' { name = 'My awesome game type!' }

client_script 'mymode_client.js'

Любой новый ресурс, который вы создадите, вероятно, захочет новейших игровых функций. Для этого и предназначено. Вы можете прочитать об этом в другом месте на этом сайте документации, если вы когда-нибудь почувствуете необходимость узнать больше. Чтобы указать, предназначен ли этот ресурс для gta5, rdr3 или , следует использовать переменную.fx_versioncommongame

С другой стороны, он говорит, что это, по сути, тип игры, и что он называется «Мой потрясающий тип игры!». Если вы просто создаете «автономный» дополнительный ресурс, вы, вероятно, не хотите включать строку.resource_typemapmanagerresource_type

Наконец, он указывает среде выполнения сценариев, что клиент должен загрузить сценарий с именем . Если бы это был lua-скрипт, он бы сказал, или если бы это был C#, это, вероятно, было бы , но на данный момент мы учим JavaScript, поэтому просто забудьте об этом.client_scriptmymode_client.jsmymode_client.luaMyModeClient.net.dll

Наконец, мы должны сделать файл, вызываемый в папке ресурсов.mymode_client.jsmymode

Дополнительные сведения о файлах манифеста ресурсов см. в разделе [ссылка на манифест ресурса][manifest-reference].

Написание кода

Теперь, когда вы настроили свой проект и среду JavaScript, мы можем начать писать код.

В файл поместим следующее содержимое:client.js

const spawnPos = [686.245, 577.950, 130.461];

on('onClientGameTypeStart', () => {
  exports.spawnmanager.setAutoSpawnCallback(() => {
    exports.spawnmanager.spawnPlayer({
      x: spawnPos[0],
      y: spawnPos[1],
      z: spawnPos[2],
      model: 'a_m_m_skater_01'
    }, () => {
      emit('chat:addMessage', {
        args: [
          'Welcome to the party!~'
        ]
      })
    });
  });

  exports.spawnmanager.setAutoSpawn(true)
  exports.spawnmanager.forceRespawn()
});

Возможно, вы видели это в документации [JavaScript runtime][javascript-runtime]. Это сложно, особенно если вы не привыкли к концепции первоклассных функций. Вы также можете написать его по-другому, используя глобальные / локальные функции - но это просто немного странно.

Давайте пройдемся по этому шагу, с аннотированной версией.

// Define a local variable called `spawnPos` with a coordinate somewhere on the map
const spawnPos = [686.245, 577.950, 130.461];

/* 
 * Add an event handler for the (local) event called 'onClientGameTypeStart'. It takes
 * no arguments in this case, since our resource is a game type and you can only run one
 * at once, that means this will basically run when we start ourselves on the client. Nice!
 */
on('onClientGameTypeStart', () => {
  /*
   * Set an automatic spawn callback for the spawn manager. Normally, this works using
   * hardcoded spawn points, but since this is a scripting tutorial we'll do it this way.
   * The spawn manager will call this when the player is dead or when forceRespawn is called.
   */
  exports.spawnmanager.setAutoSpawnCallback(() => {
    // spawnmanager has said we should spawn, let's spawn!
    exports.spawnmanager.spawnPlayer({
      // this argument is basically an object containing the spawn location...
      x: spawnPos[0],
      y: spawnPos[1],
      z: spawnPos[2],
      // ... and the model to spawn as.
      model: 'a_m_m_skater_01'
    }, () => {
      /*
       * A callback to be called once the player is spawned in and the game is visible
       * in this case, we just send a message to the local chat box.
      */
      emit('chat:addMessage', {
        args: [
          'Welcome to the party!~'
        ]
      })
    });
  });

  // Enable auto-spawn.
  exports.spawnmanager.setAutoSpawn(true)

  // And force respawn when the game type starts.
  exports.spawnmanager.forceRespawn()
});

Краткое упоминание о разнице между клиентскими и серверными скриптами: большая часть того, что вы будете делать в FiveM, будет сделана с помощью клиентских скриптов, так как в текущих версиях нет взаимодействия с игровым функционалом в серверных скриптах, если вы не используете OneSync. Серверные сценарии должны использоваться для выполнения сценариев действий между клиентами (с использованием событий клиент-сервер) и для обеспечения «источника доверия» для различных действий, таких как хранение/загрузка данных в постоянной базе данных.

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

Запуск этого

Вы, вероятно, надеетесь, что сможете запустить этот небольшой пример - ну, надеюсь, у вас уже есть работающий экземпляр FXServer - если нет, следуйте руководству для этого.

После запуска FXServer выполните команду в консоли. Это перечитает каждый файл для каждого установленного вами ресурса, так как вы, вероятно, только что запустили сервер, это на самом деле не нужно, но если у вас уже запущен сервер, это просто хорошая идея™.refreshfxmanifest.lua

Наконец, выполните в консоли и подключитесь к серверу с помощью удобной кнопки клиента FiveM в режиме разработчика (или просто войдите на вкладку прямого подключения, или, если вы использовали порт по умолчанию, нажмите эту полезную ссылку на ПК, на котором у вас установлен FiveM).start mymodelocalhostlocalhost

Как только игра загрузится, вы должны увидеть себя где-то нерестящимся - надеюсь, на большой сцене!

Держите игру запущенной (и, возможно, установите ее в безрамочный или оконный режим в параметрах игры) и Alt-Tab обратно в ваш редактор кода - у нас есть еще много работы!

Перезапуск ресурсов

Глупо закрывать игру и сервер и перезапускать их для итерации на вашем ресурсе. Конечно, вы также можете перезапустить свой ресурс.

Давайте попробуем несколько разных точек появления.

Замените строку (первую) следующей:spawnPosmymode/mymode_client.js

const spawnPos = [-275.522, 6635.835, 7.425]

Затем в консоли сервера выполните волшебную команду . Вы должны (снова) увидеть «Добро пожаловать на вечеринку!», упомянутый в вашем чате, и оказаться на пирсе, а не на сцене.restart mymode

Расширяя это

Вы, вероятно, захотите сделать больше. Для этого вам придется научиться называть аборигенов, что не имеет ничего общего с коренными народами и на самом деле является меткой R* для «игровых функций скрипта». Есть много тонкостей, связанных с правильным вызовом аборигенов - для полной справки см. специальный раздел для этого - но мы начнем с простого пока.

Глупым способом «этот троп снова» мы сделаем команду, которая породит автомобиль. Локально. Потому что никто не заботится о сервере, когда они начинают.

В нижней части экрана добавьте следующий код:mymode_client.js

RegisterCommand('car', (source, args, raw) => {
  // TODO: make a vehicle! fun!
  emit('chat:addMessage', {
    args: [`I wish I could spawn this ${(args.length > 0 ? `${args[0]} or` : ``)} adder but my owner was too lazy. :(`]
  });
}, false);

Начиная уже, мы видим вызов функции. Мы не определили эту функцию. Что ж, мы (как и команда FiveM) это сделали, но не тогда, когда вели вас, читатель, через это удивительно написанное чудо гида. Это означает, что он должен прийти откуда-то еще!

И, угадайте, это на самом деле REGISTER_COMMAND! Щелкните эту ссылку, и вы перейдете к документации для этого нативного носителя. Выглядит это примерно так:

// 0x5fa79b0f
// RegisterCommand
void REGISTER_COMMAND(char* commandName, func handler, BOOL restricted);

Мы будем в основном заботиться об имени во второй строке (как используется в коде JS выше) и аргументах.RegisterCommand

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

Сама функция получает аргумент, который является , который действительно имеет значение только в том случае, если вы работаете на сервере (это будет идентификатор клиента игрока, который ввел команду, действительно полезная вещь, которую нужно иметь), и массив, который в основном является тем, что вы вводите после команды, например, чтобы в конечном итоге быть или быть .sourceargs/car zentornoargs["zentorno"]/car zentorno unused["zentorno", "unused"]

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

Давайте перезапустим ресурс и посмотрим, что получится. Выполнить , затем в поле чата клиента (по умолчанию) введите . Вы увидите, что окно чата жалуется, что вы были слишком ленивы, чтобы реализовать это. Мы покажем им, что вы абсолютно не ленивы, и на самом деле реализуем это сейчас.restart mymodeT/car zentorno

Реализация автомобильного спауна

Это много шаблонного кода, и мы захотим сделать это правильно, так как многие люди будут копировать этот пример, поэтому он может показаться немного ошеломляющим.

По сути, мы сделаем следующее:

  1. Проверьте, действительна ли переданная модель. Невесело пытаться породить «картофель», когда нет транспортного средства с таким названием.
  2. Загрузите модель. Вам нужно будет явно управлять каждой моделью, которую вы используете, это правила, первоначально определенные R*.
  3. Дождитесь загрузки модели. Да, игра будет продолжать работать асинхронно.
  4. Выясните, где находится игрок после загрузки.
  5. Создайте транспортное средство! Потрясающе, наконец-то вы становитесь креативными.
  6. Посадите игрока в транспортное средство.
  7. Убирайтесь, так как мы аккуратные люди и 🚮 все.

Поехали!

Замените бит, который вы только что вставили, на это, и не волнуйтесь, мы объясним это, прежде чем вы сможете сказать «ленивый» дважды:

Delay = (ms) => new Promise(res => setTimeout(res, ms));

RegisterCommand('car', async (source, args, raw) => {
  // account for the argument not being passed
  let model = "adder";
  if (args.length > 0)
  {
    model = args[0].toString();
  }

  // check if the model actually exists
  const hash = GetHashKey(model);
  if (!IsModelInCdimage(hash) || !IsModelAVehicle(hash))
  {
    emit('chat:addMessage', {
      args: [`It might have been a good thing that you tried to spawn a ${model}. Who even wants their spawning to actually ^*succeed?`]
    });
    return;   
  }

  // Request the model and wait until the game has loaded it
  RequestModel(hash);
  while (!HasModelLoaded(hash))
  {
    await Delay(500);
  }

  const ped = PlayerPedId();

  // Get the coordinates of the player's Ped (their character)
  const coords = GetEntityCoords(ped);

  // Create a vehicle at the player's position
  const vehicle = CreateVehicle(hash, coords[0], coords[1], coords[2], GetEntityHeading(ped), true, false);

  // Set the player into the drivers seat of the vehicle
  SetPedIntoVehicle(ped, vehicle, -1);

  // Allow the game engine to clean up the vehicle and model if needed
  SetEntityAsNoLongerNeeded(vehicle);
  SetModelAsNoLongerNeeded(model);

  // Tell the player the car spawned
  emit('chat:addMessage', {
    args: [`Woohoo! Enjoy your new ^*${model}!`]
  });
}, false);

Для этого используется МНОГО аборигенов. Мы свяжем некоторые из них и объясним сложные части.

Шаг 1: Проверка

Мы начали с проверки названия автомобиля. Если он не задан (то есть аргументов для команды нет), мы по умолчанию будем использовать . В любом случае, он хранится в переменной.adder

Мы хотим, чтобы хэш-ключ от этого транспортного средства работал с игровым движком, поэтому мы вызываем GET_HASH_KEY и сохраняем возвращенное в переменной. Затем мы проверяем, находится ли автомобиль в образе компакт-диска, используя IS_MODEL_IN_CDIMAGE. Это в основном означает «зарегистрировано ли это в игре». Мы также проверяем, является ли это транспортным средством, использующим IS_MODEL_A_VEHICLE. Если какая-либо проверка не удалась, мы сообщаем об этом игроку и возвращаемся от команды.numberhash

Шаг 2: Загрузка модели

Теперь мы вызываем REQUEST_MODEL для загрузки фактической модели транспортного средства, используя хэш, который у нас есть из шага 1.

Шаг 3: Ожидание загрузки модели

Мы зацикливаем вызовы HAS_MODEL_LOADED, чтобы проверить, удалась ли загрузка. Поскольку это цикл, и мы совместно многозадачны, вам придется дать игре время для запуска - в противном случае она даже не закончит загрузку, и игра, к сожалению, зависнет. В отличие от Lua и C#, у нас нет встроенного или вызывающего, поэтому нам нужно создать свой собственный. Мы определили функцию в глобальном объеме нашего скрипта. Он ожидает указанное количество миллисекунд, а затем возвращает объект Promise обратно в сценарий.WaitDelayDelay

Как только модель будет загружена, мы продолжим.

Шаг 4: Получение позиции игрока

Физические воплощения игроков идентифицируются по их , что является сокращением от «пешеход». Это термин GTA, и он обычно означает «все, что живет и имеет ноги». Мы используем PLAYER_PED_ID, чтобы получить локальный (в основном, тот, кто выполняет эту команду) пед игрока.ped

После того, как у нас есть пед и мы сохраняем его в переменной, мы получаем позицию педа игрока, используя GET_ENTITY_COORDS. Поскольку пед является сущностью (то же самое касается транспортных средств и некоторых других вещей), этот натив используется для получения их позиции. Этот собственный, возвращает массив .number[]

Шаг 5: Создание транспортного средства

Мы используем CREATE_VEHICLE, чтобы, ну, создать транспортное средство. Тем временем мы пробрались в вызов, чтобы получить направление игрока, используя GET_ENTITY_HEADING, что заставляет автомобиль появляться лицом в том же направлении, что и игрок.

Это соглашение в нативных носителях создания сущностей о создании транспортного средства с сетевым объектом (), но не о том, чтобы сделать его объектом миссии (). Обычно вы хотите первое, или никто другой не увидит транспортное средство - и вы не захотите второе, так как вы не пишете полный сценарий миссии R*.true, falsetruefalse

Шаг 6: Установка игрока в транспортное средство

Поскольку теперь у нас есть пед и транспортное средство, мы можем использовать SET_PED_INTO_VEHICLE для размещения педали в транспортном средстве. Как говорится в документации, это водительское сиденье транспортного средства.-1

Шаг 7: Очистка

Игре нравится, когда вы убираете за собой, и поскольку мы больше ничего не делаем с транспортным средством или моделью в этом скрипте, мы позволим игре управлять этим. Это то, для чего мы используем SET_ENTITY_AS_NO_LONGER_NEEDED и SET_MODEL_AS_NO_LONGER_NEEDED.

Наконец, мы говорим игроку, чтобы он наслаждался своим новым транспортным средством.

Запуск этого

В вашей серверной консоли (да, вы можете разделить вещи точкой с запятой) и попробуйте в игровом клиенте (который к настоящему времени должен быть действительно надоест возрождаться). Теперь у вас будет свой собственный Rocket Voltic!refresh; restart mymode/car voltic2

Серверные скрипты

Вероятно, вы также захотите написать сценарии, которые взаимодействуют с сервером. Этот раздел еще предстоит написать. :-(


Введение в написание сценариев