Factorio: Создание мода

Правила форума
Здесь обсуждаются только игры, игровые процессы, и все что касается игр!
Запрещено:
1 обсуждать средства взлома!
2 использовать не литературную лексику!
3 оскорблять словами или действиями посетителей форума!
4 не соблюдать тематику форума!
5 спамить! в любых проявлениях! (реклама, антиреклама, ссылки! и т.п.)
6 вставлять ссылки на "левые" сайты.
7 использовать материалы сайта без письменного разрешения администрации сайта!
Ответить
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Factorio: Создание мода

Сообщение nucleon »

Создание своего мода:
вот API которое можно использовать:
  • reload() — Эта функция позволяет перезагрузить изученную технологию на картах,
    полезно если вы внесли правки, а новую карту вам создавать не хочется.
  • forse = LuaForse — Какая сила применяет эту технологию (Игрок, строение, поротивник)
    эту строку пропускаем всегда, пока еще никто не нашел ей применения,
    да и впрочем бесполезна она, но любезный разработчик на всякий случай дал нам её.
  • name = string — Имя технологии
  • localised_name = string — Локализованное имя
    (Но ведь мы помним, что мы все делаем через locale.cfg?)
  • enabled = bool — Строки блокировки на подобие строки в рецептах,
    в принципе ей не пользуются. Разве что разблокировать через скрипт.
    1. Для начала если нужно «заблокировать» все наши рецепты у предметов, то есть, каждому рецепту добавляем строку:
      enabled = false либо enabled = "false" разницы никакой.
  • upgrade = bool — Является указание на то, улучшение это или нет
  • prerequisites = dictionary string → LuaTechnology — Таблица технологий которые должны быть исследованы, чтобы эта технология стала доступной для исследования
  • research_unit_count = uint — Какие и сколько баночек на 1 исследование
  • research_unit_energy = double — Сколько времени на 1 исследование.
  • order = string — строка сортировки технологий
Структура папок мода
  • Существуюут зарезервированные имена
    • campaigns
    • locale
    • Scenarios
    • migration
    В остальном предоставляется полная свобода в создании папок и файлов
    но разработчики придерживаются своего метода:
    • В оригинальной игре все предметы, рецепты, и файлы содержаться в папке Prototypes.
      Графика — в папке Graphics.
      Звуки — в Sounds.
      Тем самым разработчики разбивают все файлы по типу.

      Внутри папок же они проводят разбиение по подтипу: например, в Prototypes идет разбиение на папки Recipes, Entity, Items, Technologies.
      Это гарантирует вам быстрое нахождение предмета в папках, но, если у вас будет много всего, будет довольно трудно найти конкретный предмет.

info.json
Данный файл содержит информацию о моде
и то что видит пользователь перед установкой мода:
{
  • "name": "Tested-mod",
    "version": "0.0.1",
    "title": "Tested-mod 0.0.0.1",
    "author": "mr.HardDrive",
    "factorio_version": "1.0",
    "dependencies": ["base >= 1.0"],
    "description": "this is a unique test mod."

}
  • Версия мода всегда записывается как 3 числа через точки. Разработчики объясняют это так:
    • Первое — Крупные обновления, Кардинальные изменения.
      Второе — мелкие обновы, добавление пары предметов,
      Третье — багфиксы

    Вроде все понятно из описания =)
thumbnail.png
Превью вашего мода
Описания нет, он подхватывается автоматически
проверенный размер 144x144
в остальном описания не заслуживает
data.lua
Главный файл вашего мода!

Этот файл будет автоматически запускаться при включении мода.
Любые другие файлы lua будут игнорироваться.

Внутри data.lua находится команда require( )
Команда прописываеться в начале файла.
Внутри скобок указывается путь к подключаемому lua файлу в кавычках, (!!!)который начинается из корня мода.
Названия папок пишутся с учетом регистра и разделяются точками.
Сам файл пишется без расширения «.lua».
Файлы можно подключать где угодно (то есть можно создавать технологию, а в ней подключить список рецептов, и т.д.).
Tehnology.lua
Технологии
[2spoiler=Tehnology.lua]Для настроек технологий отвечает файл Tehnology.lua
  • в начале идет строка инициализатор дополнения - data:extend({ })
    внутри этих двойных скобок пишем уже со своими скобками (в формате json) описание нашей технологии.
    type = "technology",
    • Категория объекта - или то где он будет находиться!

    name = "Bochka",
    • имя объекта (начальное, или дефолтное, будет основным, если не указана локализация!)

    icon = "__base__/graphics/icons/fluid/empty-crude-oil-barrel.png",
    • картинка технологии, и хоть в api про них ничего не сказано, но в игре их обязательно нужно указывать

    icon_size = 32,
    • НЕ обязательно, но если картинку обрезает, указываем её размер (картинка всегда квадрат)
      в версии 1.0.0 - этот размер вроде бы увеличили до 128!

    effects =
    • описание того, что будет делать Технология после исследования (json! - потому в своих скобках)
    1. type =
      тип действия эффекта:
      • "unlock-recipe", - открывает рецепт
    2. recipe =
      • указывает имя рецепта

    prerequisites = {},
    • в скобках идет список технологий, которые должны быть исследованы перед этим

    unit =
    • список требований к выполнению рецепта
      1. count = 35,
        • Количество исследований
      2. ingredients =
        • список ингридиентов, что и сколько
          1. {"science-pack-1", 1}
            • ресурс и количество
              для рецептов есть несколько типов:
              1. science-pack-1 устарело,"automation-science-pack"
              2. science-pack-2 устарело, "logistic-science-pack"
              3. science-pack-3 устарело,
              4. ...
              5. alien-science-pack
      3. time = 30
        • время одного исследования
[3spoiler=Пример]

data:extend({
{
type = "technology",
name = "Bochka",
icon = "__base__/graphics/icons/fluid/empty-crude-oil-barrel.png",
icon_size = 32,
effects =
{
  • {
    • type = "unlock-recipe",
      recipe = "empty-barrel-M"

    },

    {
    • type = "unlock-recipe",
      recipe = "fill-barrel"

    },

    {
    • type = "unlock-recipe",
      recipe = "empty-barrel"

    },

},

prerequisites = {},

unit =
{
  • count = 35,
    ingredients =
    {
    • {"science-pack-1", 1},

    },
    • time = 30

    },

order = "barrel"
},
})
[/3spoiler][/2spoiler]
settings.lua
settings-updates.lua
settings-final-fixes.lua
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »

Слои игры:
Вот список слоев:
  • "ground-tile"
    • - Слой перемещения персонажа (1-й слой)
  • "water-tile"
    • - Слой не доступный ля перемещения персонажа (0-й слой)
  • "resource-layer"
    • - Слой Руд (3-й слой)
  • "floor-layer"
    • - Слой Бетона либо кирпичей (2-й слой)
  • "object-layer"
    • - Слой объектов (Высший 4-тый слой)
  • "player-layer"
    • - Слой персонажа (Высший 4-тый слой)

Слой персонажа не используется ничем кроме персонажа, Хотя он и эквивалентен слоям объектов.
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »

Идеология файлов мода:
  • info.json
    - тут только то, что мы увидем в описании мода
    структура:
    для версии игры >1.1 она такова:
    Внимание!: json - капризный формат, копипаст может нормально не работать, проверяем структуру!

    Код: Выделить всё

    {
        "name": "имя",
        "version": "0.1.6",
        "factorio_version": "1.1",
        "title": "Отображаемый заголовок",
        "author": "Никнейм",
        "contact": "",
        "homepage": "",
        "dependencies": [
          "base >= 1.1.0",
          "? bzfoundry >= 0.2.1",
          "? bztitanium >= 1.2.0",
          "? bzlead >= 1.2.0",
          "? bzzirconium >= 0.6.0",
          "? bztungsten >= 0.6.0",
          "? bzcarbon >= 0.3.0",
          "? bztin",
          "? space-exploration >= 0.5.100",
          "? aai-industry",
          "? Krastorio2",
          "? deadlock-beltboxes-loaders",
          "? DeadlockCrating"
        ],
        "description": "описание которое увидит пользователь"
    }
    
    Где:
    • Обязательные:
      • name - название мода
      • factorio_version - версия фактории на которую рассчитан мод
      • version - версия мода, должна совпадать с версией указанной в названии
        (по не проверенным данным при отсутствии или несовпадении данных - может не работать)
      • dependencies - список зависимых и/или рекомендуемых модов
        • в данном случае base - это указание на базовый мод. т.е на саму factorio
        знак "?" - обозначает необязательность зависимости
    • Необязательные:
    • title - заголовок, имя которое будет отображаться в списке модов
    • author - имя автора
    • contact - контактные данные, можно e-mail
    • homepage - страничка с мода
    • description - описание для пользователя, то что будет отображено в кратко информации о моде

      начиная с версии 1.0 некоторые необязательные параметры должны быть в файле, но могут быть не заполнены
  • data.lua
    - основной фаил мода, в нем размещается почти все!
    а так-же вызываются другие файлы, если это нам необходимо
    Проверяем формат файла: *.lua
    структура файла:
    • подключение файла может быть вызванно в любом месте файла для этого служит команда:
      require("путь к вызываемому файлу/имя_файла_без_разширения.")
      Пример подключения файла gas.lua из вложенной папки prototipes:
      require("prototypes/gas")
      количество подключенных файлов ограничено только особенностями языка LUA
      однако, требует проверку порядка используемых ресурсов, т.е. нельзя добавить рецепт, добавляющий предмет, а описание этого предмета сделать позже...
      Я пришел к выводу, что для понимания того что и где искать проще разделить и вынести из файла data.lua асновную логики по загружаемым файлам в следующем порядке:
      1. entities
        - сущьности....
      2. items
        - это то что мы можем создавать физически
      3. recipes
        - рецепты, то как мы будем получать эти items
      4. technologies
        - список технологий открывающий наши рецепты
      5. и тд. и тп.

      разделение по файлам только в голове, так что все это условно!
    в итоге типовой data.lua выглядит так: require("entities")
    require("items")
    require("recipes")
    require("tehnology")
  • control.lua(обязательный)
    - в нем описываются скрипты необходимые для работы мода
  • LICENSE(необязательный)
    txt - файлик в лицензией.... если нет будет использоваться дефолтный...
    • #Поскольку этап настроек загружается первым, данные прототипа или удаленный интерфейс недоступны.
    • settings.lua(необязательный)
    • settings-updates.lua(необязательный)
    • settings-final-fixes.lua(необязательный)
[/b]
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »

items.lua
пример

Код: Выделить всё

data:extend({
  {
    type = "item",
    name = "aircraft_carrier",
    icon = "__ProtossCarrier__/graphics/Carrier_128_pr.png",
    icon_size = 128,
    subgroup = "raw-material",
    order = "aircraft_carrier",
    stack_size = 1,
  },
})
все что находится между data:extend({ и закрывающими блоком }) есть интересующие нас объекты.
каждый блок экранирован своими скобками { ... }, сами данные указываются в формате файла *.lua
если их несколько - они разделяются запятыми:[/b]
{
  • type = "item",
    name = "aircraft_carrier",
    icon = "__ProtossCarrier__/graphics/Carrier_128_pr.png",
    icon_size = 128,
    subgroup = "raw-material",
    order = "aircraft_carrier",
    stack_size = 1,

}
где:
type - указание на тип данных в данном случае всегда "item"
name -название объекта
icon и icon_size - путь к картинке и ее размер в пикселях
subgroup - подгруппа в которую следует отнести данный "item", от нее зависит какими дополнительными свойствами он будет обладать
order - ????
stack_size - кол-во предметов, которое можно поместить в одну ячейку инвентаря или сундука
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »

Локализация:
перевод существующих названий объектов на другие языки:
  1. в папке с модом создаем папку с зарезервированным именем: locale
  2. создаем в ней подпапку с именем локали для которой выполняем перевод.
    Например с "en" или "ru"
  3. в ней создаем файлик с именем locale.cfg
    получим приблизительно такую иерархию:
    • mods
      • %наш_мод%
        • locale
          • ru
            • locale.cfg
          • en
            • locale.cfg

    пример файла можно найти в папке с игрой: %factorio%/data/base/locale/en/base.cfg
    тут-же можно подсмотреть название разделов...
    к примеру
    в моем моде будет несколько разделов:

    Код: Выделить всё

    [item-name]
    ...
    
    [recipe-name]
    ...
    
    [technology-name]
    ...
    
[/b]
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »

settings.lua(необязательный)
  • Создание
    Настройки мода определяются и изменяются с помощью таблицы данных на этапе настройки. Это работает так же, как и другие прототипы. Примером может быть:
    data:extend({
    • {
      • type = "bool-setting",
        name = "my-mod-test-setting",
        setting_type = "runtime-global",
        default_value = true

      }

    })
    Где:
    • name - строка - обязательно.
      • Имя прототипа настроек должно быть уникальным, чтобы избежать конфликтов модов, поскольку настройки модов являются глобальными для всех модов.
        Из-за этого рекомендуется ставить перед настройками мода имя вашего мода, в данном примере «my-mod».
    • type - строка - обязательно.
      • Существует четыре типа настроек мода:
        • bool-setting - флажок true/false
          • default_value - логическое значение - обязательно.
            Определяет значение параметра по умолчанию, в данном случае установлен флажок или нет.
            принудительное_значение — логическое значение — необязательно.
            Загружается только если hidden = true. Это заставляет настройку иметь это значение. Это может быть полезно для совместимости модов.
        • int-setting - 64-битное целое текстовое поле со знаком (или раскрывающийся список выбора)
          • default_value - int64 - Обязательный.
            Определяет значение параметра по умолчанию.
          • minimum_value — int64 — необязательно.
            Определяет наименьшее возможное число.
          • maximum_value — int64 — необязательно.
            Определяет максимально возможное число.
          • allowed_values — массив int64 — необязательно.
            Позволяет заставить игрока выбирать между определенными числами, создает раскрывающийся список вместо текстового поля.
            Если задано только одно допустимое значение, настройки принудительно должны иметь это значение.
        • double-setting — текстовое поле двойной точности с плавающей запятой (или раскрывающийся список выбора)
          • default_value — двойное — обязательно.
            Определяет значение параметра по умолчанию.
          • minimum_value — двойное — необязательно.
            Определяет наименьшее возможное число.
          • maximum_value — двойное — необязательно.
            Определяет максимально возможное число.
          • allowed_values - массив двойных значений - Необязательный.
            Позволяет заставить игрока выбирать между определенными числами, создает раскрывающийся список вместо текстового поля.
            Если задано только одно допустимое значение, настройки принудительно должны иметь это значение.
        • string-setting - строковое текстовое поле (или раскрывающийся список выбора)
          • default_value — строка — обязательно.
            Определяет значение параметра по умолчанию.
          • allow_blank — bool — необязательно. - По умолчанию: ложь
            Определяет, может ли пользователь сделать текстовое поле пустым и применить этот параметр.
          • auto_trim - логическое значение - Необязательно. - По умолчанию: ложь
            Должны ли вводимые пользователем значения удалять пробелы с обоих концов строки.
          • allowed_values — массив строк — необязательно.
            Позволяет заставить игрока выбирать между определенными строками, создает раскрывающийся список вместо текстового поля.
            Строки в раскрывающемся списке могут быть локализованы (переведены) и могут иметь всплывающую подсказку, см. ниже[0].
            Если задано только одно допустимое значение, настройки принудительно должны иметь это значение.
    • localised_name - локализованная строка — необязательно.
    • localised_description - локализованная строка — необязательно.
    • order - строка - обязательно
      Свойство порядка можно использовать для изменения порядка настроек мода в графическом интерфейсе настроек.
      Настройки мода отсортированы
      • first by mod
        сначала по моду
      • then by the setting "order" string
        затем по настройке строки "order"
      • then finally by the setting name.
        затем, наконец, по имени настройки.

      Дополнительные сведения об использовании строки порядка см. в разделе Типы/порядок.[1]
    • скрытый - bool - Необязательный.
      • Свойство hidden можно использовать, чтобы скрыть настройки мода от графического интерфейса, чтобы игроки не могли их увидеть или изменить.
        Однако другие моды по-прежнему могут получить доступ к скрытым настройкам.[2]
    • setting_type - строка - Обязательный.
      Графический интерфейс настроек мода. Доступен из главного меню → Настройки → Настройки мода.
      Существуют общие виды настроек:
      • startup: этот тип настроек доступен на стадии прототипа и не может быть изменен во время выполнения.
        Они должны быть установлены на одинаковые значения для всех игроков на сервере.
      • runtime-global: этот тип настроек является глобальным для всей сохраненной игры и может быть изменен во время выполнения.
        На серверах только администраторы могут изменять эти настройки.
      • runtime-per-user: Этот тип настройки доступен только во время выполнения на этапе control.lua, и у каждого игрока есть свой собственный экземпляр этой настройки.
        Когда игрок присоединяется к серверу, его локальная настройка «сохранять настройки мода для каждого сохранения» определяет, синхронизируются ли установленные локальные настройки с загруженным сохранением или используются настройки сохранения.


    Локализация:
    • Локаль для настроек мода работает как любая другая локаль в игре.
      Названия групп для имени и описания настройки (всплывающая подсказка): «mod-setting-name» и «mod-setting-description».
      Выпадающие элементы строковых настроек могут быть локализованы в группе «string-mod-setting», но игра возвращается к простому отображению имени выпадающего элемента, если локализация не найдена.
      Пример локализации настроек мода, который будет установлен в "locale/en/locale.cfg":
    [mod-setting-name]
    my-mod-test-setting=Localized test setting name

    [mod-setting-description]
    my-mod-test-setting=Localized test setting description

    [string-mod-setting]
    #<setting-name>-<dropdown-item-name>=<translated dropdown item>
    my-mod-string-test-setting-item-1=Item 1 localized string

    [string-mod-setting-description]
    #<setting-name>-<dropdown-item-name>=<tooltip of dropdown item>
    my-mod-string-test-setting-item-1=Item 1 localized tooltip

    Использование:
    • Чтение настроек:
      • При доступе к любой настройке мода вам нужно будет конкретно получить доступ к значению настройки.
        Тип данных значения зависит от типа параметра. Для строковых параметров, использующих набор допустимых значений, значением параметра является одно из исходных строковых значений, определенных в прототипе, локализация игнорируется.
      • На этапе прототипа вы можете получить доступ к настройкам settings_type «startup», проиндексировав settings.startup с именем настройки.
        Пример:
      • --in settings.lua:
        data:extend({
        • {
          type = "int-setting",
          name = "my-mod-stone-wall-stack-size",
          setting_type = "startup",
          minimum_value = 1,
          default_value = 100
          }

        })

        --in data.lua:
        data.raw.item["stone-wall"].stack_size = settings.startup["my-mod-stone-wall-stack-size"].value
      • На этапе управления доступ к настройкам setting_type "runtime-global" можно получить с помощью settings.global["setting-name"] (см. LuaSettings).
        Доступ к настройкам settings_type «время выполнения для пользователя» осуществляется с помощью settings.get_player_settings(<PlayerIdentification>)["setting-name"] или game.players[<PlayerIdentification>].mod_settings["setting-name"].


        Пример:
      • --in settings.lua:
        data:extend({
        • {
          • type = "string-setting",
            name = "my-mod-always-difficult",
            setting_type = "runtime-global",
            default_value = "yes",
            allowed_values = {"yes", "no"}

          },
        • {
          • type = "bool-setting",
            name = "my-mod-kill-player-on-entity-built",
            setting_type = "runtime-per-user",
            default_value = false

          }

        })

        --in control.lua:
        script.on_init(function()
        • if settings.global["my-mod-always-difficult"].value == "yes" then
          • game.difficulty_settings.recipe_difficulty = 1
            game.difficulty_settings.technology_difficulty = 1
            game.difficulty_settings.technology_price_multiplier = 4

          end

        end)

        script.on_event(defines.events.on_built_entity, function(event)
        • local setting_value = settings.get_player_settings(event.player_index)["my-mod-kill-player-on-entity-built"].value
          if setting_value then
          • game.get_player(event.player_index).die()

          end

        end)
    • Запись в свои настройки
      • Моды могут записывать свои собственные настройки мода во время выполнения (глобальные или для каждого игрока). Это делается путем записи новой таблицы ModSetting в настройку.

        Пример:
    --in settings.lua:
    data:extend({
    • {
      • type = "string-setting",
        name = "my-mod-always-difficult",
        setting_type = "runtime-global",
        default_value = "yes",
        allowed_values = {"yes", "no"}

      }

    })

    --in control.lua:
    script.on_event(defines.events.on_rocket_launched, function()
    • settings.global["my-mod-always-difficult"] = {value = "yes"}

    end)

    • Изменение настроек другого мода

      • После создания параметра на этапе настроек он сохраняется в data.raw до конца этапа, поэтому его можно изменить из другого мода.
        Пример:
    --in settings-updates.lua:
    data.raw["string-setting"]["my-mod-always-difficult"].order = "abc"
      • Если намерение состоит в том, чтобы установить для настройки определенное значение, которое не может быть изменено игроками, можно использовать свойства hidden, allow_values и forced_value.
        Изменение существующих настроек других модов может быть полезно для пакетов модов или других целей совместимости модов.[3]
        Пример:
    --in settings-updates.lua:
    data.raw["string-setting"]["my-mod-always-difficult"].hidden = true
    data.raw["string-setting"]["my-mod-always-difficult"].allowed_values = {"no"}
    data.raw["string-setting"]["my-mod-always-difficult"].default_value = "no"


    • Советы:
      • Не делайте условно «требовать (...)» вещи в зависимости от настроек мода: это нарушит проверку CRC, и люди получат ошибки, пытаясь использовать ваш мод в мультиплеере. «требовать (...)» все, а затем условно добавить значения в data.raw, используя настройки.
      • Вы должны кэшировать таблицу настроек внутри события, в котором вы ее используете.
        Доступ к ней относительно дорог (примерно так же дорог, как доступ к game.*prototypes[...]), поэтому при многократном доступе к ней в одном и том же событии вы должны установить локальную переменную к нему (внутри события) для повышения производительности.
      • Если вы хотите кэшировать параметры запуска и времени выполнения вне событий, вам необходимо убедиться, что локальная переменная параметров settings_type «runtime-global» обновлена в событии on_runtime_mod_setting_changed.
      • Если вы хотите определить, установлен ли определенный мод на этапе настроек, вы можете использовать if mods["another-mods-name"], как и на этапе данных.

    [2spoiler=raw]

    Код: Выделить всё

    data:extend({
        {
            type = "bool-setting",
            name = "my-mod-test-setting",
            setting_type = "runtime-global",
            default_value = true
        }
    })

    Код: Выделить всё

    --in settings.lua:
    data:extend({
        {
            type = "int-setting",
            name = "my-mod-stone-wall-stack-size",
            setting_type = "startup",
            minimum_value = 1,
            default_value = 100
        }
    })
    
    --in data.lua:
    data.raw.item["stone-wall"].stack_size = settings.startup["my-mod-stone-wall-stack-size"].value

    Код: Выделить всё

    --in settings.lua:
    data:extend({
        {
            type = "string-setting",
            name = "my-mod-always-difficult",
            setting_type = "runtime-global",
            default_value = "yes",
            allowed_values = {"yes", "no"}
        },
        {
            type = "bool-setting",
            name = "my-mod-kill-player-on-entity-built",
            setting_type = "runtime-per-user",
            default_value = false
        }
    })
    
    --in control.lua:
    script.on_init(function()
        if settings.global["my-mod-always-difficult"].value == "yes" then
            game.difficulty_settings.recipe_difficulty = 1
            game.difficulty_settings.technology_difficulty = 1
            game.difficulty_settings.technology_price_multiplier = 4
        end
    end)
    
    script.on_event(defines.events.on_built_entity, function(event)
        local setting_value = settings.get_player_settings(event.player_index)["my-mod-kill-player-on-entity-built"].value
        if setting_value then
            game.get_player(event.player_index).die()
        end
    end)
    [/2spoiler]
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »


Обзор

  • Предупреждение:
    • Код, окрашенный в зеленый цвет, должен быть включен в мод, который будет создан в этом руководстве;
      Если читатель последует за ним. Лучший способ сделать это — скопировать и вставить, чтобы обеспечить точное воспроизведение.
      Всякий раз, когда код добавляется в мод, комментарий Lua с именем файла будет в начале зеленого поля. Поместите код в поле в этот файл.
      Например:
      --control.lua

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

      Это руководство было обновлено до версии 1.1, поэтому все зрители в будущем должны принять к сведению, что могут быть внесены некоторые незначительные изменения, и должны просмотреть журналы изменений до текущей версии.
  • Терминология, используемая в моддинге
    • Mod
      • Скрипт или серия скриптов, которые позволяют вносить изменения в игру через API.
    • Entity
      • Сущность в Factorio — это все в игре, что не является концепцией, событием или плиткой.
        Примеры сущностей включают персонажа, сборочную машину, кусачку и т.д.
        Это могут быть «машины» или свободно движущиеся объекты, такие как персонаж.
    • Character
      • Фактическая сущность, через которую игрок манипулирует миром.
    • Player
      • Все данные, которые определяют игрока, такие как имя пользователя, время онлайн или текущий уровень масштабирования.
    • Prototype
      • Прототип описывает экземпляр сущности, предмета или рецепта и т. д., что-то вроде шаблона. Он определяет статистику, например, что на самом деле представляет собой сущность, размер стека предмета, ингредиенты рецепта и т. д. Прототип используется для создания экземпляра сущности/предмета/и т. д., и многие функционально идентичные сущности/предметы/и т. д. будут использовать один и тот же прототип.
    • Surface
      • Поверхность немного похожа на измерение. Он состоит из ландшафта, такого как трава, песок и вода, и всех объектов на поверхности. По умолчанию в Factorio есть только одна поверхность, называемая внутри «nauvis» или game.surfaces[1], но моды могут создавать дополнительные поверхности через API.
    • Event
      • Событие — это повторяющееся... событие, которое запускается внутри игры. Есть несколько событий, к которым моды могут подключать функции, такие как on_entity_died и т. д. Подробнее об этом в разделе сценариев управления.
    • Item
      • Предметы — это то, что перемещается в инвентаре, вставщиками, на ремнях и т. д. Каждый предмет в игре является экземпляром соответствующего прототипа предмета.


      Дополнительные термины могут быть объявлены и определены позже в этом руководстве.
  • Описание:
    • Factorio — это игра, написанная на языке C++ с API, предоставленным Wube (разработчиками Factorio) для модификации Factorio на языке программирования Lua (версия 5.2.1).
      Этот API позволяет добавлять сценарии в процесс инициализации Factorio, чтобы изменять его без раскрытия исходного кода базовой игры или изменения памяти. Это может отличаться от других игр, предлагающих моддинг, но это более профессиональный и правильный способ поддержки моддинга.
      Для помощи рекомендуется использовать wiki, информацию о классах, информацию о событиях, информацию о прототипах
  • Как Factorio загружает моды
    • Порядок загрузки. Внутри этапов моды загружаются по зависимости, а затем по алфавиту.
    • Factorio имеет три типа зависимостей.
      • Существуют обязательные зависимости и необязательные зависимости.
        Третий тип, ограничительные зависимости, не влияет на порядок модов и вместо этого предотвращает загрузку игры, если найден другой мод.
        Требуемые зависимости всегда загружаются первыми. Игра не сможет инициализироваться, если один из них отсутствует. Необязательные зависимости загружаются первыми, если они есть, но не обязательно. Это полезно для включения бонусных функций, если моды используются вместе. Необходимые зависимости должны использоваться для библиотек модов и аналогичной инфраструктуры.
    • Этап настроек (settings.lua)
      Самый первый этап мода, который загружается при инициализации Factorio, — это этап настроек.
      Этот этап используется для определения всех настроек мода, которые позже отображаются в графическом интерфейсе настроек внутриигрового мода, и не имеет других функций или возможностей.
      1. При прохождении этого этапа игра просматривает все моды в поисках файла с именем settings.lua.
      2. После выполнения settings.lua для всех модов выполняется файл settings-updates.lua каждого мода и,
      3. наконец, вызывается файл settings-final-fixes.lua каждого мода.

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

      Этап настроек не имеет доступа к данным прототипа или среды выполнения, поскольку он загружается до этих этапов.
      Ожидается, что настройки будут иметь определенный формат, и весь дополнительный код будет удален после завершения этапа.
      Настройки мода не рассматриваются в этом руководстве, дополнительную информацию о них см. в разделе Учебник:Настройки модов.
    • Этап данных (data.lua)
      Это наиболее ограниченная часть инициализации Factorio, здесь вы мало что можете сделать, кроме объявления прототипов технологий, сущностей, предметов и многого другого.
      Такие вещи, как манипулирование файлами, влияние на мир и т.д., заблокированы/недоступны.
      Фактически, любые сделанные функции или изменения будут отброшены, так как сеанс lua завершится.
      Вы также не можете возиться с таблицей данных, это приведет к ошибке или будет проигнорировано.
      При использовании data:extend({}) ожидается определенный формат, подробнее об этом позже.

      1. При прохождении этого этапа игра ищет во всех модах файл с именем data.lua.
      2. После выполнения data.lua для всех модов выполняется data-updates.lua каждого мода и,
      3. наконец, вызывается файл data-final-fixes.lua каждого мода.

      Эти 3 разных этапа этапа данных позволяют изменять данные других модов, не полагаясь на то, что зависимости загружаются последними.
      Например, базовый мод создает рецепты бочек для всех (тогда присутствующих) жидкостей в data-updates.lua.
      Это означает, что если вы добавите жидкость в data.lua, то в data-updates.lua базового мода будут добавлены рецепты бочек, независимо от того, зависит ли ваш мод от базы.
      Конечно, это также означает, что если вы добавите жидкость в data-final-fixes.lua, он будет создан после того, как запустится код бочки в data-updates.lua, поэтому рецепт бочки не будет создан, даже если это необходимо. Из-за этого и подобных взаимодействий модов рекомендуется создавать прототипы как можно раньше.
      Таким образом, не используйте data-final-fixes.lua, чтобы исключить жидкость из барреля, вместо этого создайте ее в data.lua и используйте «auto_barrel = false» для жидкости.

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

      Все прототипы задокументированы здесь на вики: Определения прототипов.
    • Миграции (migrations.lua)
      • Миграции — это скрипты, которые используются для «исправления» сохранения после обновления мода.
        Всякий раз, когда имена прототипов меняются в моде, необходимо настроить миграции, чтобы заменить все старые экземпляры прототипа объекта в мире.
        Это необходимо сделать для всех обновленных сущностей, иначе старые сущности будут удалены из мира, что является непрофессиональным запасным вариантом, из-за которого вы не нравитесь пользователям.
        Хотя в этом руководстве миграция не рассматривается, существует множество ресурсов по миграции, которые можно найти в сообществе и на сайте API.

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

      В большинстве модов есть файл с именем control.lua. Этот файл содержит скрипты, которые заставляют мод выполнять определенные действия во время игры, а не просто добавлять сущности в игру.
      На этом этапе запускается файл control.lua каждого мода в его собственном экземпляре lua (это означает отсутствие взаимодействия без специальной настройки), которым он будет владеть до конца игрового сеанса.
      Во время игрового сеанса доступ ко всем столам, предоставляемым игрой, может осуществляться внутри обработчиков событий. (Подробнее об этом ниже.) Поскольку control.lua запускается каждый раз, когда создается или загружается файл сохранения, вам не нужно перезапускать игру, чтобы увидеть изменения, внесенные в файл control.lua.
      Просто перезапустите или перезагрузите сохранение, чтобы повторно запустить этот этап.
      Есть несколько других предостережений на этом этапе, чтение страницы жизненного цикла данных на сайте API дает лучший обзор.

      Задокументированный этап управления задокументирован на lua-api.factorio.com.
  • Основные компоненты любого мода Factorio
    • В обычном моде есть несколько компонентов, которые заставляют мод работать.
      Моды, которые определяют новые объекты, должны будут объявить эти объекты в data.lua, data-updates.lua, data-final-fixes.lua или другом файле, требуемом одним из этих трех.
      Для модов с внутриигровыми эффектами также потребуется файл control.lua для добавления сценариев.
      Моды с настраиваемыми пользовательскими настройками будут использовать settings.lua для описания этих настроек.
      Моды, определяющие любой игровой элемент с читаемым именем, также могут предоставлять каталог locale и подкаталоги с именами/описаниями на одном или нескольких языках.
nucleon
Admin
Сообщения: 1122
Зарегистрирован: 14 мар 2009, 15:45
Контактная информация:

Re: Factorio: Создание мода

Сообщение nucleon »

Создание прототипа

Теперь в Factorio есть два способа создания прототипов. Есть короткий путь и длинный путь.
  • Длинный путь требует создания полного определения прототипа на основе документации,
  • а короткий путь просто использует функцию lua для копирования и изменения уже существующего определения. Ради этого урока мы сделаем это коротким путем.

  • Пример короткого пути создания прототипа
    В item.lua скопируйте и вставьте следующее:
    Пример item.lua

    --item.lua -- этот комментарий только для нас, он поясняет что данные относятся к файлу item.lua
    local fireArmor = table.deepcopy(data.raw["armor"]["heavy-armor"]) -- копируем таблицу, определяющую элемент тяжелой брони, в переменную fireArmor
    -- на самом деле "data.raw" - это таблица с "raw" данными, которая доступна только до непосредственного запуска игры.
    -- она содержит все игровые "прототипы" которые будут в ней использоваться (items, recipe, и другие)
    -- (Вы можете посмотреть реализацию в файле /factorio/data/core/lualib/dataloader.lua).
    -- на этапе контроля (когда игра запущена), вы не можете прочитать эти данные;
    -- вместо этого вы считываете обработанные значения через API из различных типов, таких как LuaEntityPrototype.


    -- далее правим уже данные в переменной
    fireArmor.name = "fire-armor"
    fireArmor.icons = {
    • {
      • icon = fireArmor.icon,
        tint = {r=1,g=0,b=0,a=0.3}

      }
    ,
    }

    fireArmor.resistances = {
    • {
      • type = "physical",
        decrease = 6,
        percent = 10

      },
      {
      • type = "explosion",
        decrease = 10,
        percent = 30

      },
      {
      • type = "acid",
        decrease = 5,
        percent = 30

      },
      {
      • type = "fire",
        decrease = 0,
        percent = 100

      }

    }
    Пример recipe.lua

    --recipe.lua -- этот комментарий только для нас, он поясняет что данные относятся к файлу recipe.lua
    -- аналогично поступаем и с рецептом
    local recipe = table.deepcopy(data.raw["recipe"]["heavy-armor"])
    recipe.enabled = true
    recipe.name = "fire-armor"
    recipe.ingredients = {{"copper-plate",200},{"steel-plate",50}}
    recipe.result = "fire-armor"

    -- вставляем измененные данные в "базу" игры
    data:extend{fireArmor,recipe}
    Пример в "raw" для копирования "ctrl+c"

    Код: Выделить всё

    --item.lua
    
    local fireArmor = table.deepcopy(data.raw["armor"]["heavy-armor"]) -- copy the table that defines the heavy armor item into the fireArmor variable
    
    fireArmor.name = "fire-armor"
    fireArmor.icons = {
      {
        icon = fireArmor.icon,
        tint = {r=1,g=0,b=0,a=0.3}
      },
    }
    
    fireArmor.resistances = {
      {
        type = "physical",
        decrease = 6,
        percent = 10
      },
      {
        type = "explosion",
        decrease = 10,
        percent = 30
      },
      {
        type = "acid",
        decrease = 5,
        percent = 30
      },
      {
        type = "fire",
        decrease = 0,
        percent = 100
      }
    }
    
    local recipe = table.deepcopy(data.raw["recipe"]["heavy-armor"])
    recipe.enabled = true
    recipe.name = "fire-armor"
    recipe.ingredients = {{"copper-plate",200},{"steel-plate",50}}
    recipe.result = "fire-armor"
    
    data:extend{fireArmor,recipe}
  • Подробнее о data.raw

    Когда Factorio инициализируется, все прототипы помещаются в таблицу с именем data.raw.
    Эта таблица содержит все типы прототипов, а внутри этих типов — отдельные прототипы, идентифицируемые по имени:

    • local prototype = data.raw["тип-прототипа"]["внутреннее-имя"].


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

    • local fireArmor = table.deepcopy(data.raw["armor"]["heavy-armor"])


    Мы назначаем переменную с именем fireArmor, которая содержит нашу копию определения тяжелой брони.
    Обратите внимание, что в data.raw есть таблица типов, которая содержит все доспехи, а конкретный доспех, который мы ищем, называется Heavy-Armor.
    Мы можем найти тип прототипа тяжелой брони и внутреннее название в информационном поле ее страницы на этой вики и просто скопировать оттуда.
    Кроме того, мы можем найти тип прототипа предмета и внутреннее имя, открыв игру, вставив предмет в наш инвентарь,
    а затем нажав SHIFT + CTRL + F, наведя указатель мыши на предмет. Это откроет графический интерфейс проводника прототипов, в котором есть строки, показывающие имя и тип элемента.

    В качестве другого примера, прототип персонажа будет, согласно информационному блоку на странице:
    • data.raw["character"]["character"]

    Поскольку персонаж есть персонаж, его тип соответствует его имени. Вы можете определить новый тип персонажа с модом.
    Посмотреть все доступные поля прототипа персонажа можно в документации: Prototype/Character.

    В этот момент вы можете подумать: «Могу ли я модифицировать существующие прототипы Factorio, не создавая новых?» Что ж, ответ - да!
    Вы просто получите доступ к таблице data.raw во время инициализации в data-final-fixes.lua, если хотите запускать после всех других модов и изменить свойство.
    Например, сделайте так, чтобы железный сундук имел 1000 единиц здоровья:

    • data.raw["container"]["iron-chest"].max_health = 1000


    Причина, по которой этот код находится в data-final-fixes.lua, заключается в том, что это последний запуск файла после запуска всех файлов мода.
    Это предотвратит (в некоторой степени) то, что ваши изменения будут испорчены другими модами.
    Конечно, несовместимость все же возможна. Вы должны указать все, что вам известно, в описании вашего мода. Опять же, следует изучить документацию разработчиков по этому вопросу.

    Это также может быть применено к другим модам, а не только к базе Factorio. Вы можете изменить мод,
    если вы добавите мод (который вы изменили с помощью своего мода) в свои зависимости, чтобы он загружался первым.
  • Подробнее о сценариях управления:
    Чтобы доработать мод, нам нужно, чтобы он был больше, чем простая элемент брони (из примера выше).
    Мы хотим, чтобы броня создавала огонь на земле, когда мы идем в броне.
    Событие, которое мы собираемся использовать, называется on_player_changed_position, так как мы хотим, чтобы огонь возникал при движении игрока.

    В папке нашего мода создайте файл с именем control.lua. Игра автоматически запустит этот файл, поэтому требовать его не нужно.

    Внутри control.lua скопируйте и вставьте следующее:
    control.lua

    --control.lua

    script.on_event(defines.events.on_player_changed_position,
    • function(event)
        • local player = game.get_player(event.player_index) -- получить игрока, который переместился
          -- если они носят нашу броню
          if player.character and player.get_inventory(defines.inventory.character_armor).get_item_count("fire-armor") >= 1 then
          • -- создать огонь там, где они стоят
            player.surface.create_entity{name="fire-flame", position=player.position, force="neutral"}

        end

      end

    )
    control.lua RAW

    Код: Выделить всё

    --control.lua
    
    script.on_event(defines.events.on_player_changed_position,
      function(event)
        local player = game.get_player(event.player_index) -- get the player that moved            
        -- if they're wearing our armor
        if player.character and player.get_inventory(defines.inventory.character_armor).get_item_count("fire-armor") >= 1 then
           -- create the fire where they're standing
           player.surface.create_entity{name="fire-flame", position=player.position, force="neutral"} 
        end
      end
    )
    комментарии lua в приведенном выше коде нужен, чтобы объяснить каждый шаг.
    Его довольно легко понять, и он показывает, как получить текущую броню, которую носит персонаж игрока, с помощью defines.inventory.character_armor, которая является константой инвентаря. Вы можете прочитать список определений здесь.
Ответить