moonloader:exports

Экспорт/Импорт

Экспорт и импорт – концепция, введённая в версии .023, реализованная для осуществления взаимодействия между разными активными скриптами, позволяет обмениваться данными и вызывать функции. Самое наглядное применение данной системы – это создание API, но область применения этим не ограничивается.
Не является альтернативой или заменой стандартной функции require.

В одном скрипте указывается, что он экспортирует какие-то данные, будь то обычные числа или строки, либо таблицы и функции. Таким образом он открывает доступ к каким-то своим данным для других скриптов, затем другие скрипты могут обращаться к экспортированным данным этого скрипта и взаимодействовать с ним.
Экспортирование данных осуществляется добавлением значений в глобальную таблицу EXPORTS, либо прямым назначением переменной EXPORTS любого значения 1).
Экспорт – операция предоставления открытого доступа.

Давайте рассмотрим скрипт, экспортирующий данные. Назовём его exporter.lua:

local shared_value = 0
-- можно добавлять экспорты таким способом
EXPORTS = {
  api_version = 1.0,
  static_text_value = 'exports example',
  useless_function = function()
  end
}
-- и таким
function EXPORTS.print_name()
  print(thisScript().name)
end
 
function EXPORTS.set_shared_value(new_value)
  shared_value = new_value
end
 
function EXPORTS.get_shared_value()
  return shared_value
end
-- только все функции и значения, находящиеся в таблице EXPORTS будут доступны другим скриптам
 
local vk = require 'vkeys'
function main()
  while true do
    wait(0)
    if wasKeyPressed(vk.VK_1)
      -- но НЕЛЬЗЯ это делать таким способом
      -- почему - об этом ниже
      EXPORTS.some_value = 1337
    end
    if wasKeyPressed(vk.VK_OEM_PLUS) then
      -- однако можно обновлять какое-то внутреннее значение и предоставить возможность получать и изменять его посредством функций
      shared_value = shared_value + 1 
    end
    if wasKeyPressed(vk.VK_ENTER) then
      print(shared_value)
    end
  end
end

Такой скрипт не будет ничем отличаться от любого другого, пока какой-то из скриптов не импортирует его.
Импорт осуществляется двумя способами: функцией import или обращением к свойству LuaScript.exports объекта LuaScript. В большинстве случаев рекомендуется использовать функцию import.
Импорт – операция получения доступа к экспортированным данным.

Следующий скрипт импортирует предыдущий скрипт exporter.lua и взаимодействует с ним:

local exporter = import('exporter.lua') -- можно и без расширения
 
local vk = require 'vk'
function main()
  -- экспортирующий скрипт выведет своё название от своего имени.
  -- т.е. любая экспортируемая функция выполняется внутри экспортирующего скрипта
  exporter.print_name()
  -- можно получать значения констант напрямую
  print('exporter.lua API Version:', exporter.api_version, 'text:', exporter.static_text_value)
  while true do
    wait(0)
    if wasKeyPressed(vk.VK_2) then
      -- будет сгененрировано случайное значение и это значение будет передано функции EXPORTS.set_shared_value из скрипта exporter.lua.
      exporter.set_shared_value(math.random(1, 1337))
      -- можно вызвать EXPORTS.get_shared_value из exporter.lua и вывести полученное значение
      print(exporter.get_shared_value())
    end
  end
end

Первое импортирование скрипта приводит к полному копированию (кроме функций) его экспортируемых данных в импортирующий скрипт, а повторное импортирование будет возвращать уже загруженные значения. Именно поэтому изменение значений экспортов становится бессмысленным после первого импортирования, и это может привести к несоответствиям между скриптами, если какой-то скрипт загрузит список импортов рано, а другой с задержкой. В связи с этим для правильной реализации доступа к изменяющимся данным нужно использовать функции.
В отличие от стандартной функции require, функция import следует системным правилам навигации по пути файла (require использует точку в качестве разделителя директорий), т.е. путь к экспортируемому скрипту может быть любым путём, поддерживаемым операционной системой. Правила поиска файла по заданному пути такие же, как у функции script.load.


1)
экспортировать и передавать другому скрипту можно любые значения, в т.ч. вложенные таблицы и функции, но обмен потоками (thread), и пользовательскими данными (userdata) приведёт к неопределённому поведению