Гайд по моддингу

Введение

Итак, вы решили написать мод для Love, Money, Rock'n'Roll. 

По большей части вам понадобится любой текстовый редактор (желательно с поддержкой YAML-синтаксиса) — например, Notepad++, однако хватит и обычного блокнота.

Папка модификаций

Все локальные модификации для игры подгружаются из папки Love, Money, Rock'n'Roll_Data\mods.

Моды из Steam Workshop хранятся внутри папки steamapps\workshop\content\615530, которая расположена на том диске, на котором установлена игра.

Сам мод может храниться в двух видах:

.scenario-архивы предназначены преимущественно для распространения модификаций вне Steam Workshop.

Steam Workshop поддерживает только моды в подпапках, любые другие моды (в .scenario-архивах или .mod-бандлах из старой системы модов) не будут распознаваться игрой.

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

Метаданные

Метаданные

Файлы метаданных

Игра получает информацию о моде из следующих файлов:

  1. meta.yaml
  2. resources.yaml

meta.yaml отвечает за информацию о моде во внутриигровом мод-селекторе;
resources.yaml — за всё остальное — это основной файл, который вам придётся редактировать чаще всего.

Оба файла должны быть расположены в корневой директории мода, содержимое файлов должно иметь корректный YAML-синтаксис и верно указанные параметры (об этом будет далее).

YAML достаточно простой и интуитивный, но если у вас возникли сложности, можете воспользоваться специальным ресурсом для валидации YAML-синтаксиса.

В YAML нельзя использовать табуляцию — используйте пробелы.

Метаданные

Языковые ноды

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

Значением такого параметра может быть просто текст:

title: Название мода

В таком случае Название мода будет отображаться на русском для всех языков.

Чтобы локализировать параметр для разных языков, нужно указать код языка и текст:

title:
    ru: Название мода
    en: Mod title
    common: Текст, который будет выводиться для любого другого языка*, перевод для которого не указан

Поддерживаемые языковые коды:

* В игре на данный момент всего два языка — русский и английский.

Метаданные

Ресурсные ноды

Большая часть параметров в resources.yaml определяет какие-либо внешние ресурсы, используемые в игре: фоны, звуки, спрайты персонажей и их имена, цвета, глобальные переменные и прочее. Такие параметры для удобства будут называться ресурсными нодами.

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

У таких имён есть ограничения на используемые символы, а именно: допускаются только латинские (английские) символы, цифры и нижнее подчёркивание. Использовать кириллицу, пробелы или какие-то либо другие символы нельзя.

Пример определения фона с ID bus_stop внутри resources.yaml:

# resources.yaml
---
  bg:
    bus_stop: bg/bus_stop.jpg

Строчка bus_stop: bg/bus_stop.jpg — ресурсный нод, содержащий путь к ассету.

Пример определения цвета с ID dark_pink:

# resources.yaml
---
  colors:
    dark_pink: #b00b69

ID регистронезависимы

Метаданные

Ассеты

Пути ассетов

Различные ноды часто принимают в качестве аргумента путь к какому-либо ассету (файлу).

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

Например, у нас есть обложка мода — cover.jpg, которая лежит в папке images. Корректный путь к ней будет выглядеть так:
images/cover.jpg

Если же обложка лежит в корневой директории, достаточно просто указать имя файла:
cover.jpg

Если ваш мод находится внутри .scenario-архива, учитывайте регистр при указании путей. Также регистр важен на UNIX-системах (Linux, macOS, Android и т.п.).

Если ваш файл называется Cover.jpg, а в пути вы указали cover.jpg — будет выдана ошибка.

Виды ассетов

Всего существует 3 основных вида ассетов, их можно загружать из директории мода и из Unity-каталогов:

Также существует ещё 2 вида, которые можно загружать только из Unity-каталогов:

У каждого параметра, принимающего ассет(ы) в качестве аргумента, будут указаны виды ассетов, которые он принимает.

Метаданные

Списки

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

Например:

# resources.yaml
---
  bg:
    bus_stop: bg/bus_stop.jpg
    ext_road_day: bg/ext_road_day.jpg

  sound:
    blow_with_the_fires: sound/blow_with_the_fires.ogg
    no_tresspassing: sound/no_tresspassing.ogg

Параметры bg и sound в данном примере — списки.

meta.yaml

Файл с основной информацией о модификации. По наличию этого файла в подпапке / .scenario-архиве игра распознает мод.

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

Содержимое файла имеет следующий вид:

---
    title: Название мода        
    description: Описание мода
    version: 1.0.0
    cover: cover.jpg

Наличие любого из параметров необязательно, однако сам файл (пусть даже и пустой) обязательно должен быть в корневой папке мода, чтобы мод распознался игрой.

Параметры

title

Тип: языковой нод

Название мода. Поддерживает тэги разметки Rich Text.

description

Тип: языковой нод

Описание мода. Поддерживает тэги разметки Rich Text.

version

Тип: текстовый нод

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

cover

Тип: путь к файлу изображения

Обложка мода.

Файл обложки должен весить не более 2048 килобайт. 

Предпочтительное разрешение: 445x200.

resources.yaml

resources.yaml

Описание

Файл, содержащий информацию о всех ресурсах мода. Именно в нём прописываются все невстроенные в игру ресурсы, которые вы хотите использовать в игре. 

Поддерживает следующие параметры:

Большая часть из этих параметров — списки, внутри которых прописываются те или иные ресурсы.

resources.yaml

backdrop_bg

Тип: список ресурсных нодов

Типы принимаемых ассетов: 


Определяет фоны для команды backdrop.

Пример использования:

# resources.yaml
---
  backdrop_bg:
    eli_1: backdrops/eli_1.jpg
    himitsu_2: backdrops/himitsu_2.jpg
    kagome_3: ~@bundle[prefab]://backdrop_kagome_3.prefab #подгрузка префаба из каталога "bundle"

resources.yaml

backdrop_text

Тип: список языковых нодов

Определяет локализируемый текст для команды backdrop.

Пример использования:

# resources.yaml
---
  backdrop_text:
    day1: День 1
    day2: 
      ru: День 2
      en: Day 2
    day3: День 3

resources.yaml

bg

Тип: список ресурсных нодов

Типы принимаемых ассетов: 

Определяет фоны для команды scene.

Ноды данного параметра могут принимать путь к одному или нескольким ассетам:

# resources.yaml
---
  bg:
    ext_road_day: bg/ext_road_day.jpg

В таком случае указанный ассет — bg/ext_road_day.jpg — будет использоваться вне зависимости от настроек анимации фонов в игре.

Чтобы задать разные ассеты для разных настроек анимации, следует указывать пути внутри параметров static и anim:

# resources.yaml
---
  bg:
    ext_road_day:
      static: bg/ext_road_day.jpg
      anim: ~@bundle[prefab]://bg/ext_road_day.prefab #префаб анимированного фона из каталога "bundle"
    int_bus_day:
      static: bg/int_bus.jpg
      anim: bg/int_bus_2.jpg #статичное изображение, однако оно будет использоваться, если в настройках игры включена анимация фонов

Если один из параметров не указан (static или anim), то в обоих режимах будет использоваться ассет указанного параметра.

resources.yaml

cg

Тип: список ресурсных нодов

Типы принимаемых ассетов: 

Определяет цг для команды scene.

Синтаксис полностью идентичен bg, отличается только название нода: 

# resources.yaml
---
  cg:
    d1_rena_sunset: cg/d1_rena_sunset.jpg
    d3_dv_guitar:
      static: cg/d3_dv_guitar.jpg
      anim: ~@bundle[prefab]://cg/d3_dv_guitar.prefab


resources.yaml

catalogs

Тип: список ресурсных нодов

Определяет Unity-каталоги для загрузки ассетов.

В нодах указывается путь к .json файлу собранного каталога:

# resources.yaml
---
  catalogs:
    bundle: catalogs/bundle/catalog.json #определение каталога "bundle"

Каталог должен лежать внутри папки мода и не может находится внутри другого каталога

Также можно указать каталоги для разных платформ:

# resources.yaml
---
  catalogs:
    bundle: #определение каталога "bundle" под разные платформы
      windows: catalogs/bundle/win/catalog.json
      linux: catalogs/bundle/linux/catalog.json
      macos: catalogs/bundle/mac/catalog.json
      android: catalogs/bundle/android/catalog.json
      ios: catalogs/bundle/ios/catalog.json

Список доступных плафторм:

Если платформа не указана (как в первом примере), то будет выставлено значение по умолчанию — windows.

После определения каталога, вы можете использовать ассеты из него при помощи следующего синтаксиса:
~@имяКаталога://адресАссета

Тип ассета указывается в квадратных скобках после имени каталога:
~@имяКаталога[типАссета]://адресАссета

Если тип не указан, будет использован тип по умолчанию в зависимости от параметра.

Примеры использования путей с каталогом "bundle":
~@bundle://bg/bus_stop # ассет с адресом bg/bus_stop из каталога
~@bundle[prefab]://bg/bus_stop # префаб с адресом bg/bus_stop из каталога

resources.yaml

characters

Тип: список

Определяет статичные спрайты персонажей для команды show.

Внутри нода прописываются ноды с параметрами статичных (неанимированных) спрайтов персонажей:

# resources.yaml
---
  characters:
    dv:
      # ... параметры
    un:
      # ... параметры
    sl:
      # ... параметры
    us:
      # ... параметры

Каждый спрайтовый нод может содержать следующие параметры:

poses

Тип: список

Определяет позы спрайта.
Под позами понимаются различные вариации спрайта:

mt_poses.png

3 различных позы на примере спрайта из Бесконечного Лета

Каждая поза может содержать несколько параметров: 

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          parts:
           # ... параметры
          canvasSize: 900 1080
          positions:
           # ... параметры
          sizes:
           # ... параметры
          spritecolors:
           # ... параметры

parts

Тип: список

Определяет части, из которых собирается спрайт. 

Части могут быть двух типов:

Тип ассетов у частей — texture.

Постоянные части

Постоянные части видны всегда и никогда не меняются (например, тело персонажа).

Определяются следующим образом:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          parts:
            body: sprites/mt/mt_1_body.png # тело персонажа, которое должно отображаться всегда
            
          # ... остальные параметры

На примере выше мы определили часть body — тело спрайта, на которое будут накладываться остальные элементы.

Непостоянные части

Непостоянные — соответственно, те части, которые могут меняться. Это эмоции, одежда, различные аксессуары и прочее. Такие части объединяются в группы, которые позволяют менять активную (отображаемую) часть из сценария.

Непостоянные части определяются так же, как и постоянные, только внутри отдельного нода, начинающегося со знака ~ — такой нод называется группой:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          parts:
            body: sprites/mt/mt_1_body.png # это постоянная часть, которую мы определили ранее
            ~uniform: # группа uniform
              pioneer: sprites/mt/mt_1_pioneer.png # пионерская форма
              dress: sprites/mt/mt_1_dress.png # платье
              swimsuit: sprites/mt/mt_1_swim.png # купальник
              
          # ... остальные параметры

У частей спрайта в группе также может указываться параметр position, синтаксис аналогичен.

На примере выше мы создали группу uniform с различными вариациями одежды, которые можно использовать в игре. Однако мы не указали, какая часть должна отображаться по умолчанию — в случае, если мы явно не обозначили это в сценарии. 

Чтобы сделать какую-либо часть в группе частью, отображаемой по умолчанию, можно воспользоваться параметром default:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          parts:
            body: sprites/mt/mt_1_body.png # это постоянная часть, которую мы определили ранее
            ~uniform: # группа uniform
              default: pioneer # по умолчанию при вызове спрайта будет выводиться пионерская форма
              parts:
                pioneer: sprites/mt/mt_1_pioneer.png # пионерская форма
                dress: sprites/mt/mt_1_dress.png # платье
                swimsuit: sprites/mt/mt_1_swim.png # купальник                
              
          # ... остальные параметры

Как видно из примера, ID части, выводимой по умолчанию, прописывается в ноде default, а сами части — в parts.

Если нод default не указан, то по умолчанию ни одна часть не будет выводиться.

Позиционирование частей

Каждой части спрайта можно задать положение относительно канваса:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          parts:
            body: 
              asset: sprites/mt/mt_1_body.png
              position: 0 100
              
          # ... остальные параметры

На примере выше изображение будет смещено на 100 пикселей по вертикали относительно левого верхнего угла канваса спрайта. Ассет же прописывается в ноде asset.

Использование параметра position у части спрайта возможно только если указан параметр canvasSize у позы.

Порядок наложения частей

Части спрайта (будь то постоянная часть или группа) накладываются друг на друга согласно порядку, в котором они определены:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          parts:
            body: sprites/mt/mt_1_body.png # сначала будет выведено тело
            ~uniform: # затем форма
                pioneer: sprites/mt/mt_1_pioneer.png # пионерская форма
                dress: sprites/mt/mt_1_dress.png # платье
                swimsuit: sprites/mt/mt_1_swim.png # купальник
            ~face: # затем лицо
                normal: sprites/mt/mt_1_normal.png # нейтральное лицо
                smile: sprites/mt/mt_1_smile.png # улыбка
                sad: sprites/mt/mt_1_sad.png # грустное лицо
              
         # ... остальные параметры

canvasSize

Тип: текстовый нод

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

Значение должно состоять из двух целых чисел, разделённых пробелом, и представлять собой корректное разрешение:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          canvasSize: 900 1080 # 900x1080              
          
          # ... остальные параметры

positions

Тип: список

Определяет именованные положения спрайта относительно игровой сцены. Не стоит путать с параметром positions у частей спрайта.

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          positions:
            center: 0 0 # центр
            left: -0.5 0 # лево
            right: 0.5 0 # право
          
          # ... остальные параметры

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

Указанные внутри нода персонажа позиции будут переопределять одноимённые позиции выше по иерархии.

Также можно указать значение только для одной оси, прописав . в качестве значения для второй:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          positions:
            center: -0.5 . # изменена только X-координата
            left: . -0.5 # изменена только Y-координата
          
         # ... остальные параметры

Значение для недостающей координаты будет браться из позиций с таким же ID выше по иерархии, если же таких нет — будет выставлен 0.

Подробнее о положениях можно почитать здесь.

sizes

Тип: список

Определяет именованные размеры спрайта относительно игровой сцены. Синтаксис схож с positions:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          sizes:
            normal: 1 1
            close: 2 .
          
          # ... остальные параметры

Внутри каждого нода можно также прописать позиции — они будут использоваться, когда у спрайта будет указанный размер:

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          positions:
            center: 0 0 # это значение будет использоваться при любых других размерах
          sizes:
            normal: 1 1
            close: 
              value: 2 .
              positions: # позиции при размере close
                center: 0 0.25 # это значение будет использоваться при размере close
          
          # ... остальные параметры

Размер в таком случае указывается внутри нода value.

На примере выше, когда у спрайта в сценарии будут прописаны size close и at center, в качестве координат для center будет использоваться значение 0 0.25, а не 0 0.

Аналогично positions, размеры, указанные внутри нода персонажа, будут переопределять одноимённые размеры выше по иерархии.

Подробнее о размерах можно почитать здесь.

spritecolor

Тип: список

Цвета для наложения на спрайт. Используются для более естественного отображения спрайтов на различных фонах (день, ночь и т.п.).

Значением может быть как цвет, заданный в colors, так и HEX-код или RGB(A)-код.

# resources.yaml
---
  characters:
    mt:
      poses:
        front_1:
          spritecolor:
            tokyo_street_sunset: #FFF1ED
 
          # ... остальные параметры

Подробнее о цветах спрайтов можно почитать здесь.

shortnames

Тип: список

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

Короткие имена прописываются так же, как прописываются позы и группы внутри сценария:

# resources.yaml
---
  characters:
    mt:
      shortnames:
        front_sd: front smile dress # или front face:smile uniform:dress

После определения коротого имени, его можно использовать внутри сценария:

show mt front_sd with dissolve

default

Тип: текстовый нод

Определяет позу и части групп, которые будут выводиться по умолчанию (если конкретные значения не указаны в команде сценария).

В качестве значения можно прописать короткое имя или позу и параметры групп:

# resources.yaml
---
  characters:
    mt:
      default: front smile dress
      # ... остальные параметры

Теперь, когда в сценарии будет прописано show mt, по умолчанию будет спавнится вариация front smile dress.

positions

Тип: список

Определяет позиции, которые могут использовать все позы спрайта. Любые позиции внутри конкретной позы будут переопределять данные позиции, если у них совпадают ID.

Синтаксис идентичен синтаксису positions внутри позы:

# resources.yaml
---
  characters:
    mt:
      positions:
        center: 0 0
        left: -0.5 0
      # ... остальные параметры

sizes

Тип: список

Определяет размеры, которые могут использовать все позы спрайта. Любые размеры внутри конкретной позы будут переопределять данные размеры, если у них совпадают ID.

# resources.yaml
---
  characters:
    mt:
      sizes:
        normal: 1 1
        close: 2 .
        far:
          value: 0.7 0.7
          positions:
            center: 0 -0.25
      # ... остальные параметры

spritecolor

Тип: список

Определяет оверлей-цвета спрайтов, которые могут использовать все позы спрайта. Любые цвета внутри конкретной позы будут переопределять данные цвета, если у них совпадают ID.

# resources.yaml
---
  characters:
    mt:
      spritecolor:
        tokyo_street_sunset: #FFF1ED
      # ... остальные параметры

resources.yaml

chibis

Тип: список
Тип принимаемых ассетов:


Добавляет изображение для команды chibi.

Синтаксис:

# resources.yaml
---
chibis:
  chibi1: images/chibi1.png
  chibi2: images/chibi2.png

resources.yaml

collections

Тип: список

В данном ноде определяются элементы галереи — фоны, цг, музыка, концовки и сноски (доступны из меню "Помощь").

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

Нод может содержать следующие параметры, каждый из которых является списком:

Все элементы в игре выводятся в том порядке, в котором они указаны (сверху вниз).

bg / cg

Тип: список

Список фонов/цг для галереи. ID каждого нода в данном списке должен соответствовать существующему фону/цг — встроенному в игру или же определённого внутри resources.yaml:

# resources.yaml
---
  bg:
    bus_stop: bg/bus_stop.jpg # определение фона bus_stop
  cg:
    d1_rena_sunset: cg/d1_rena_sunset.jpg # определение цг d1_rena_sunset

  collections:
    bg:
      bus_stop: # добавление фона bus_stop в галерею
        thumb: gallery/thumbs/bg/bus_stop_284x160.jpg # превью
    cg:
      d1_rena_sunset: # добавление цг d1_rena_sunset в галерею
        thumb: gallery/thumbs/cg/d1_rena_sunset_284x160.jpg

    # остальные параметры

Каждый нод может содержать следующие параметры:

name

Тип: языковой нод

Название фона/цг. Выводится в меню при просмотре, если у фона/цг есть вариации.

Если не указан, будет использован ID фона/цг.

thumb

Тип: ассет
Типы принимаемых ассетов: 


Файл превью для галереи.
Предпочтительное разрешение: 284x160.

variatons

Тип: список

Вариации фона/цг. Содержит ноды с вариациями, каждый из которых может содержать параметр name — название, которое будет отображаться в меню при просмотре:

# resources.yaml
---
  bg:
    bus_stop: bg/bus_stop.jpg # определение фона bus_stop
    bus_stop_day: bg/bus_stop_day.jpg # определение фона bus_stop_day
  cg:
    d1_rena_sunset: cg/d1_rena_sunset.jpg # определение цг d1_rena_sunset
    d1_rena_day: cg/d1_rena_day.jpg # определение цг d1_rena_day

  collections:
    bg:
      bus_stop: # добавление фона bus_stop в галерею
        name: "Автобусная остановка"
        thumb: gallery/thumbs/bg/bus_stop_284x160.jpg # превью
        variations: # вариации
          bus_stop_day: 
            name: "Автобусная остановка, день"
    cg:
      d1_rena_sunset: # добавление цг d1_rena_sunset в галерею
        name: "Рена"
        thumb: gallery/thumbs/cg/d1_rena_sunset_284x160.jpg,
        variations: # вариации
          d1_rena_day:
            name: "Рена, день"

    # ... остальные параметры

Вариации не могут иметь вариаций.

Вариациям можно не задавать параметр thumb, т.к. превью для них не используются.

endings

Тип: список

Список концовок, отображаемых в меню "Помощь".

Каждый нод внутри списка — языковой нод.
Поддерживают тэги разметки Rich Text.

# resources.yaml
---
  collections:
    endings:
      himitsu_good_end: Химицу, хорошая концовка
      himitsu_bad_end: Химицу, плохая концовка
      kagome_good_end: # концовка с переводами на два языка
        ru: Кагомэ, хорошая концовка
        en: Kagome, good ending

      # остальные параметры

Разблокировка той или иной концовки происходит при помощи команды внутри игрового сценария.

notes

Тип: список

Список сносок, отображаемых в меню "Помощь".
Внутри списка прописываются ID сносок:

# resources.yaml
---
notes: # определение сносок
  note1: "Сноска #1"
  note2: "Сноска #2"
  note3: "Сноска #3"

collections:
  notes: # сноски, которые должны отображаться в меню "Помощь"
    - note1
    - note2
    - note3
    

tracks

Тип: список

Список треков, отображаемых в галерее.

ID каждого нода внутри списка должен соответствовать ID встроенного в игру музыкального трека или трека, прописанного в resources.yaml.

Название трека указывается внутри нода:

# resources.yaml
---
  sound:
    echo_avenue_old: sound/music/echo_avenue_old.mp3 # определение трека

  collections:
    tracks:
      echo_avenue_old: Echo Avenue [Old Version] # добавление трека в галерею

Если название не указано, будет выведен ID трека.

Использование встроенных ресурсов

Чтобы вывести в галерее какой-либо элемент, встроенный в игру, достаточно просто прописать его ID и ID необходимых вариаций. Название и превью нужно указывать только в том случае, если вы хотите их изменить.

# resources.yaml
---
  collections:
    # для всех этих элементов будут использованы значения по умолчанию, встроенные в игру
    bg:
      tokyo_street_day:
        variations:
          tokyo_street_night:
          tokyo_street_sunset:
    tracks:
      a_painful_story:
      ddd_take_two:
    endings:
      himitsu_bad: # Химицу, плохая
      himitsu_good: # Химицу, хорошая

Обратите внимание, что после ID нода нужно ставить двоеточие, но не нужно указывать параметры.

resources.yaml

colors

Тип: список

Определяет цвета, которые можно использовать внутри игрового сценария и в параметрах resources.yaml, принимающих цвет в качестве значения.

Значением цвета может быть HEX-код или RGB(A)-код:

# resources.yaml
---
  colors:
    red_brown: "#a55e55" # HEX-код указывается в кавычках, т.к. иначе символ "#" будет расценён как начало комментария
    aquamarine: (127, 255, 212) # rgb-код
    pink_half_opacity: (255, 20, 147, 127) # rgba-код

Поддерживаемые форматы HEX-кодов:

resources.yaml

entryPoint

Тип: текстовый нод

Входная точка сценария.

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

Значение по умолчанию: day1

Пример:

# resources.yaml
---
  scenarios:
    scenario1: scenarios/scenario1.txt # определение сценария scenario1

  entryPoint: scenario1 # scenario1 будет запускаться при начале новой игры

resources.yaml

help

Тип: список

В этом ноде прописывается текст "Контактов" и "Титров" для меню "Помощь". 

Может содержать следующие параметры:

Оба параметра являются языковыми нодами и поддерживают тэги разметки Rich Text.

# resources.yaml
---
  help:
    contacts: "Текст для обратной связи"
    credits: "Текст титров"

resources.yaml

live2d_characters

Тип: список

В этом ноде определяются Live2D-спрайты персонажей.

Так же, как и в случае со статичными спрайтами, каждый спрайтовый нод может содержать следующие параметры:

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

Кроме того, Live2D спрайты также могут содержать параметр layers с информацией об анимационных слоях — синтаксис этого параметра также будет рассмотрен.

layers

Тип: список

Внутри данного параметра прописываются названия анимационных слоёв и анимаций, которые они содержат.

Слои делятся на два типа:

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

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

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

Рассмотрим процесс определения нескольких слоёв:

# resources.yaml
---
live2d_characters
  saya:
    layers:
      emotions:
        - normal
        - smile
        - sad
      hands:
        - hands1
        - hands2
        - hands3
      ~shake:
        - head

Здесь определяются 3 слоя — emotions, hands и shake. Первые два — основные слои, для эмоций и положения рук соответственно, последний — вспомогательный. Внутри нодов слоёв прописаны названия анимаций, которые этот слой содержит.

Для определения вспомогательного слоя нужно перед его именем поставить символ ~.

poses

Тип: список

Так же, как и у статичных спрайтов, внутри данного нода прописываются различные позы и их параметры.

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

Также им доступны два новых параметра:

layers внутри позы определяет слои и анимации, действительные только для этой позы (или перезаписывает их, если слой с таким же названием прописан для всего спрайта в целом).

skins же — аналог parts статичных спрайтов, в нём прописываются пути Live2D-префабов спрайта.

skins

Тип: список
Тип принимаемых ассетов: prefab

Синтаксис достаточно прост, внутри нода прописываются пути к префабам Live2D моделей:

# resources.yaml
---
live2d_characters:
  saya:
    poses:
      front:
        skins:
          school_unfiform: ~@[bundle]://characters/saya/front/school_uniform/model.prefab # путь к префабу внутри каталога

Краткая форма записи

Ноды poses и skins необязательно указывать явно, если вы не намереваетесь использовать какие-либо другие параметры. 

Допустим, тот же пример с определением позы front и скина school_uniform можно записать так:

# resources.yaml
---
live2d_characters:
  saya:
      front:
          school_unfiform: ~@[bundle]://characters/saya/front/school_uniform/model.prefab # путь к префабу внутри каталога

Если бы мы захотели указать какие-то позиции, размеры, слои анимации и прочее — необходимо было бы явно указывать названия нодов.

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

# resources.yaml
---
live2d_characters:
  saya:
    layers:
      emotions:
        - normal
        - smile
        - sad
      hands:
        - hands1
        - hands2
        - hands3
    positions:
      center: 0 -0.25
    poses:
      front:
          school_unfiform: ~@[bundle]://characters/saya/front/school_uniform/model.prefab # путь к префабу внутри каталога

Т.к. нод спрайта содержит не только позы, но и другие параметры, нам нужно явно указать название нода с позами. Внутри же нода позы front никаких других параметров, кроме скинов, нет — поэтому названием нода skins можно пренебречь. Если бы нужно было указать какие-то дополнительные параметры для позы front, скины бы прописывались внутри нода skins.

resources.yaml

menu

Тип: список

Определяет элементы кастомизации главного меню.

Доступные параметры:

Каждому элементу внутри параметров присваивается ID — целое число, которое определяет порядок выбора элементов (чем меньше число — тем выше приоритет):

# resources.yaml
---
  menu:
    bg:
      0:
        # параметры
      1: 
        # параметры
    logos:
      0:
        # параметры
      1:
        # параметры
    tracks:
      0:
        # параметры
      1:
        # параметры

Также у каждого элемента может быть задан параметр condition, в котором прописывается условие, при котором данный элемент может быть выбран для отображения.

bg

Тип: список

Список фонов для главного меню.

Фон может задаваться одним из двух параметров:


Первый используется для указания пути конкретного ассета, второй — для указания ID определённого в resources.yaml или встроенного в игру фона.

# resources.yaml
---
bg:
  bus_stop: bg/bus_stop.jpg # определение фона bus_stop

menu:
  bg:
    0:
      asset: bg/menu_bg.jpg # подгрузка фона из папки bg
    1:
      name: bus_stop # подгрузка фона bus_stop

Параметр asset принимает следующие типы:


Также можно в ноде просто указать путь до ассета без указания других параметров, в таком случае это будет равносильно указанию параметра asset:

# resources.yaml
---
bg:
  bus_stop: bg/bus_stop.jpg # определение фона bus_stop

menu:
  bg:
    0: bg/menu_bg.jpg # подгрузка фона из папки bg

Эффекты постобработки

Помимо описанных выше параметров, нод также может принимать ещё несколько параметров:

Все эти параметры — булевые переменные, т.е. их значением может быть либо true, либо false. Они отвечают за включение/отключение соответствующих эффектов пост-обработки фона в главном меню:

# resources.yaml
---
  menu:
    bg:
      0:
        name: house_mc_day
        twirl: true
        particles: true
        blur: true
        noise: true

По умолчанию значения всех параметров — true.

Также можно задать overlay-цвет для фона при помощи параметра color:

# resources.yaml
---
  menu:
    bg:
      0: # пример дневной вариации фона из главного меню игры
        name: house_mc_day
        color: "#AC8E0E32"

logos

Тип: список

Список логотипов для главного меню.

Изображение логотипа задаётся при помощи параметра asset:

# resources.yaml
---
menu:
  logos:
    0:
      asset: images/menu_logo.png

Также значением asset может быть default — в таком случае игра будет использовать встроенный логотип LMR:

# resources.yaml
---
menu:
  logos:
    0:
      asset: default # будет использован логотип Love, Money, Rock'n'Roll

Параметр asset данного нода — своего рода исключение, которое помимо пути ассета принимает и значение default.

Ещё одной особенностью параметра asset является возможность указать разные ассеты под разные языки, аналогично синтаксису языковых нодов, только в качестве значения нужно писать путь к ассету:

# resources.yaml
---
menu:
  logos:
    0:
      asset:
        ru: images/menu_logo_ru.png
        en: images/menu_logo_en.png

Аналогично bg, можно указать только путь к ассету, игнорируя остальные параметры:

# resources.yaml
---
menu:
  logos:
    0: images/menu_logo.png
    1: default

Положение и размер логотипа

Положение и размер логотипа настраиваются двумя параметрами:


Оба параметра принимают как и ID положения/размера, указанного в resources.yaml, так и числовые значения:

# resources.yaml
---
sizes:
  logo_normal: 0.8 0.8
positions:
  logo_top: 0 0.25

menu:
  logos:
    0:
      asset: images/menu_logo.png
      position: 0 0.25
      size: 0.8 0.8
    1:
      asset: images/menu_logo.png
      position: logo_top
      size: logo_normal

tracks

Тип: список

Фоновые треки для главного меню.

Аналогично нодам bg, трек указывается либо через asset, либо через name. Также можно указать только путь к ассету:

# resources.yaml
---
sizes:
  logo_normal: 0.8 0.8
positions:
  logo_top: 0 0.25

menu:
  tracks:
    0:
      asset: sound/menu_track.mp3
    1:
      name: summertime # трек, встроенный в игру    
    2: sound/menu_track.mp3 # аналогично ноду с "0"

Параметр asset принимает только один вид ассетов — sound.

Условия вывода

Каждый нод фона/лого/трека может иметь параметр condition, который отвечает за условие выбора того или иного элемента.

Условие может содержать глобальные и persistent переменные, а также значения datetime:

# resources.yaml
---
menu:
  bg: # пример вывода стандартных фонов главного меню в зависимости от времени суток
    0:
      name: house_mc_day
      color: "#AC8E0E32"
      condition: "datetime.hour >= 7 && datetime.hour < 16"
    1:
      name: house_mc_sunset
      color: "#87173E2D"
      condition: "datetime.hour >= 16 && datetime.hour < 22"
    2:
      name: house_mc_night
      color: "#3A00BE3C"
      condition: "datetime.hour >= 22 || datetime.hour < 7"

Значения глобальных переменных будут браться из continue-сохранения (которое загружается при нажатии "Продолжить" в главном меню).

Если такого нет, будут использованы значения по умолчанию.

Пустые значения

Если вы хотите не выводить вообще ничего, достаточно в качестве значения для параметра asset указать null:

# resources.yaml
---
menu:
  bg:
    0:
      asset: null # также можно указать как 0: null
  logos:
    0:
      asset: null
  tracks:
    0:
      asset: null

resources.yaml

narrators

Тип: список

Определяет имена персонажей, которые можно использовать в игровом сценарии.

Параметры:


Пример:

# resources.yaml
---
narrators:
  hi:
    name: "Химицу"
    advColor: "#91483c"
    nvlColor: "#EC7070"
    simpleAdv: true

resources.yaml

notes

Тип: список

В этом ноде определяются внутриигровые сноски.

Каждая сноска является языковым нодом и поддерживает тэги разметки Rich Text.

Пример:

# resources.yaml
---
notes:
  note1: "Сноска #1"
  note2:
    ru: "Сноска #2"
    en: "Note #2"

 

resources.yaml

particles

Тип: список
Тип ассетов: prefab

Определяет внутриигровые партикли (различные частицы, типа лепестков сакуры).

Партикли можно загружать только из Unity-каталогов — ассет должен быть префабом с компонентом Particle System.

# resources.yaml
---
catalogs:
  bundle: catalogs/bundle/catalog.json # определение каталога "bundle"

particles:
  snow: ~@bundle://particles/snow.prefab # определение партиклей "snow" из префаба внутри каталога "bundle"
resources.yaml

positions

Тип: список

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

Координаты задаются при помощи двух осей: X и Y — горизонтальной и вертикальной соответственно.

Видимое пространство находится в диапазоне от -1 до 1.
Абсолютный центр экрана — 0 0.

# resources.yaml
---
# примеры некоторых стандартных позиций спрайтов персонажей в игре
positions:
  center: 0 -0.59
  left: -0.67 -0.59
  right: 0.67 -0.59

 

resources.yaml

scenarios

Тип: список
Тип принимаемых ассетов: text

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

# resources.yaml
---
scenarios:
  day1: scenarios/day1.txt # определение сценария "day1"
  day2:
    asset: scenarios/day2.txt # определение сценария "day2"
    en: scenarios/day2_en.csv # английская локализация для "day2"

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

Параметр common внутри данного нода неприменим.

resources.yaml

sizes

Тип: список

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

В основном размеры используются для масштабирования спрайтов персонажей.

Размеры задаются двумя параметрами: шириной и высотой, разделёнными пробелом:

# resources.yaml
---
sizes:
  normal: 1 1 # определение размера "normal"

Также каждый размер может содержать внутри себя список положений, которые будут использоваться спрайтом персонажа в игре, если у него будут совпадать название размера и название позиции:

# resources.yaml
---
positions:
  center: 0 -0.59 # определение позиции "center"

sizes:
  close:
    value: 1.95 1.95 # размер указывается в параметре "value"
    positions:
      center: 0 -1.57 # переопределение положения "center" для размера "close"
      # также вместо X-координаты можно прописать точку:
      # center: . -1.57
      # в таком случае значение X будет взято из исходного положения (0 в данном случае)

Значение размера указывается внутри параметра value, а позиции — внутри списка positions.

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

В итоге спрайт в игре при размере close и положении center будет выглядеть так:

image.png

А не так:

image.png

resources.yaml

spritecolor

Тип: список

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

Цвета определяются следующим образом:

# resources.yaml
---
spritecolor:
  tokyo_street_night: "#E9F6FF"
  tokyo_street_sunset: "#FFF1ED"

Значением цвета может быть также и ID цвета, определённого в ноде colors.

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

image.png
Спрайт на ночном фоне без overlay-цвета.

image.png
Тот же спрайт, но уже с цветом.

resources.yaml

sound

Тип: список
Тип принимаемых ассетов: sound

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

Поддерживаются все форматы, распознаваемые Unity:

Чтобы звуковой файл распознался, он должен иметь корректное расширение.

Звуки определяются следующим образом:

# resources.yaml
---
sound:
  echo_avenue_old: sound/echo_avenue_old.wav
  into_the_uknown: sound/into_the_uknown.mp3

resources.yaml

transitions

Тип: список

Список различных пресетов для переходов.
Переходы бывают нескольких видов:

В backgroud, character и screen прописываются пресеты переходов, аналогично тому, как они прописываются в файле сценария:

# resources.yaml
---
transitions:
  background:
    dissolve2sec: dissolve 2 # dissolve длительностью в 2 секунды
  character:
    crossfade2sec: crossfade 2 2 # crossfade с fadeOut = 2 секундам и fadeIn = 2 секундам
    fade212: fade 2 1 2 # fade с fadeIn = 1, hold = 1 и fadeOut = 2
  screen:
    fadeRed: fade color:#FF0000 # fade с красным цветом
    hpunch2: hpunch 2 3 10 0 true # горизонтальный punch с duration = 2, strength = 3, vibrato = 10, randomness = 0 и fadeOut = true

В pattern же прописываются ассеты изображений для переходов фонов типа pattern:

# resources.yaml
---
transitions:
  pattern:
    chainsaw_pattern: images/patterns/chainsaw_pattern.jpg # определение изображения паттерна chainsaw_pattern
  background:
    chainsaw_pattern: pattern chainsaw_pattern 1.5 # определение перехода chainsaw_pattern длительностью в 1.5 секунды с использованием определенного выше изображения паттерна

///

Со списком доступных переходов и их параметрами можно ознакомиться здесь.


resources.yaml

variables

Тип: список

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

Переменные определяются следующим образом:

# resources.yaml
---
variables:
  himitsu_points: 0 # определение переменной himitsu_points со значением "0" по умолчанию
  day1_choice_made: false # переменная day1_choice_made со значением "false" по умолчанию

Значения глобальных переменных могут содержать числа, текст, булевые значения (true/false), а также различные алгебраические операции.

Значения определяемых глобальных переменных не могут содержать в себе другие переменные.

Мод-пример

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

Cover.png

Мод доступен в Steam Workshop, а также здесь.

Если вы установили мод через мастерскую, он будет расположен в папке steamapps\workshop\content\615530\3020524921.

Запуск модов

Моды запускаются из отдельной опции в игре:

image.png

В левом меню располагается список доступных модов. У каждого мода слева от названия находится иконка, обозначающая тип установленного мода:

image.png

image.png

image.png

Мод из мастерской Мод из .scenario-архива Мод внутри подпапки

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

В правом меню расположена обложка мода, его описание и кнопка активации.

В самом низу — кнопка обновления списка установленных модов (в классическом интерфейсе она находится сверху — первая кнопка слева от фильтров). 

Активация мода

При активации мода, игра начнёт сохранять всю информацию о прогрессе (сейвы, открытые предметы галереи, прочитанные строки) отдельно от основной игры, в подпапках, которые соответствуют названию файла/подпапки мода (в случае с мастерской - его ID).

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

Локальный сервер

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

Если указанный порт занят, при попытке открыть модселектор будет выведено окно с ошибкой:

image.png

Вы можете либо освободить указанный порт, закрыв программу, которая его использует, либо указать другой порт при помощи опции --local-port номер_порта при запуске игры.

Готовый проект Unity

Для создания каталогов и импорта/экспорта Live2D-моделей вы можете скачать проект для Unity 2022.3.6f1, в котором установлены все необходимые плагины и произведены все нужные настройки.

Скачать можно здесь.

Плагины

Создание каталогов

Каталоги нужны для подгрузки каких-либо ассетов Unity из бандлов.

В этой статье будет рассмотрен процесс создания бандлов и каталога для них.
О том, как добавить созданный каталог в ресурсы игры, написано здесь.

Требования

У вас должны быть хотя бы минимальные знания по работе с редактором Unity и представление об ассет-бандлах.

Для продолжения вам понадобится редактор Unity 2022.3.6 с пакетом Addressables 1.21.15, который можно установить через менеджер пакетов внутри редактора.

Работоспособность каталогов в LMR не гарантируется при использовании других версий редактора/пакета Addressables.

Платформа сборки

Каталоги собираются под текущую активную плафторму в редакторе Unity. Её можно узнать, нажав на File -> Build Settings в меню редактора Unity или нажав Ctrl + Shift + B.

Если вы хотите, чтобы ассеты из каталогов работали на нескольких платформах (Windows, Android, Linux и т.п.) — вам нужно собирать их отдельно под каждую платформу.

Настройка Addressables

Вы можете скачать готовый проект с необходимыми настройками.

После установки редактора и пакета, откройте окно редактирования групп Addressables:

Windows -> Asset Managment -> Addressables -> Groups

Если вы открываете это окно в первый раз, у вас появится сообщение о необходимости создать настройки Addressables. Нажмите Create Addressables Settings.

image.pngЭто сообщение появляется только при первом запуске

После того, как завершится создание настроек, вы увидите следующее окно:

image.png

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

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

AddressableAssetSettings

При помощи проводника проекта (по умолчанию располагается в самом низу окна редактора), найдите ассет AddressableAssetSettings, полный путь которого:
Assets/AddressableAssetsData/AddressableAssetSettings.asset

image.png

Кликните на него — в правой части окна редактора появится Inspector с настройками:

image.png

Для начала нам необходимо изменить настройки профиля по умолчанию, для этого кликните на Manage Profiles во вкладке Profiles, появится следующее окно:

image.png

Здесь нам нужно поменять настройки Remote. Нажмите на выпадающий список напротив и выберите в нём Custom.

Измените значение Remote.BuildPath на следующую строчку:
ServerData/[BuildTarget]

Затем измените значение Remote.LoadPath:
{LMR_MOD_ROOT}

Должно получиться так:

image.png

Закройте окно. Далее возвращаемся обратно к окну инспектора, и включаем чекбокс Build Remote Catalog во вкладке Catalog:

image.png

Убедитесь, что в выпадающем списке Build & Load Paths выбрано значение Remote с настройками, что мы указывали в профиле. У Build Path вместо [BuildTarget] будет указана ваша платформа — это нормально.

В этой же вкладке включаем чекбокс Only update catalogs manually:

image.png

Последняя настройка, которую нам нужно изменить у данного ассета — это Strip Unity Version from AssetBundles, которая находится на вкладке Build — её необходимо включить:

image.png

Шаблоны групп

Далее нам необходимо изменить настройки по умолчанию для создаваемых групп. Они хранятся в файле Assets\AddressableAssetsData\AssetGroupTemplates\Packed Assets.asset.

Находим этот файл, кликаем по нему и видим следующее:

image.png

Здесь нас интересуют следующие настройки:

  1. Build & Load Paths
    Необходимо в списке выбрать Remote, чтобы использовались пути, которые мы указали в настройках ассета Addressables.

  2. Use Assets Bundle Cache
    Эту настройку необходимо выключить. Значение Build & Load Paths может сброситься на Local или <custom> — в таком случае поменяйте обратно на Remote.

  3. Assets Bundle CRC
    Эту настройку также необходимо отключить. Нажмите на выпадающий список и выберите там Disabled.

  4. Bundle Naming Mode
    Настройки нейминга бандлов. Рекомендуется выставить Append Hash To Filename.

  5. Prevent Updates (вкладка Content Update Restriction)
    Включите данный чекбокс.

В итоге, после изменения настроек, шаблон будет выглядеть так:

image.png

Далее вернёмся к окну Addressables Groups. В нём сейчас всего две группы: Built In Data и Default Local Group (Default):

image.png

Нажмите на Built In Data и отключите оба чекбокса в инспекторе:

image.png

Создание групп

Как было сказано ранее, внутри окна Addressables Groups создаются различные группы ассетов — из этих групп после сборки будут созданы бандлы. Каждая группа — отдельный бандл, в котором хранятся ассеты (зависит от режима сборки, о нём будет далее).

Чтобы создать группу, нажмите правкой кнопкой мыши по свободному месту в окне и выберите Create New Group -> Packed Assets. По умолчанию название будет Packed Assets, но вы можете изменить его, кликнув правой кнопкой мыши по группе и выбрав соответствующий пункт в меню. Названия групп не играют важной роли и могут быть любыми.

Удаление группы Default Local Group (Default)

После создания новой группы, удалите группу Default Local Group (Default), либо измените её настройки в соответствии с настройками шаблона Packed Assets. Если вы удалите группу, то следующая за ней группа станет группой по умолчанию.

Режим сборки ассетов

Этот параметр называется Bundle Mode, его можно найти в окне инспектора, кликнув по любой группе:

image.png

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

Pack Together — все ассеты из группы будут упакованы в один бандл, и, соответственно, в игре будут загружаться одновременно, даже если используется только один ассет из группы. Этот режим рекомендуется ставить, если в группе находятся ассеты от какого-то одного объекта - вроде анимированного фона и частей, из которых он состоит.

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

Pack Together By Label — не используется в модах.

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

Если вы добавите в группу папку — все ассеты внутри неё будут загружаться в игре одновременно, даже если у группы стоит Pack Separately. По сути, папка - это группа внутри группы.

Добавление ассетов в группу

Чтобы добавить какой-либо ассет в группу, нужно перетащить его в необходимую группу внутри окна. 

add_to_group.gif

Также вы можете нажать на ассет и в окне инспектора включить чекбокс Addressable — в таком случае ассет будет добавлен в группу по умолчанию (вы можете перетащить его оттуда в любую группу).

Нейминг ассетов

После добавления ассета в группу, ему будет присвоено имя, соответствующее его пути внутри проекта. Такое имя называется адресом ассета (или его ключом) — именно на это имя вы будете ссылаться для загрузки ассета внутри файла ресурсов мода — resources.yaml. 

Чтобы изменить имя, кликните по ассету в группе правой кнопкой мыши и выберите Change Address:

image.png

 Ключи чувствительны к регистру.

Сборка каталога

После того, как вы создали все необходимые группы и добавили в них ассеты, вам нужно собрать бандлы и каталог для них. Делается это достаточно просто, для этого нужно в окне с группами нажать Build -> New Build -> Default Build Script:

image.png

Если это первая попытка сборки, то редактор спросит вас о необходимости включить новую систему отчётов — рекомендуем согласиться.

Если всё прошло хорошо, в консоли редактора появится следующее сообщение:

image.png

А также откроется окно с отчётом, если вы его включили:

image.png

После этого вам необходимо открыть корневую папку вашего проекта в любом файловом проводнике (не в редакторе) и найти там папку ServerData:

image.png

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

image.png

Переместите все эти файлы внутрь директории вашего мода.

После этого вы сможете указать путь к json-файлу каталога в resources.yaml и использовать ассеты из него внутри ресурсов вашего мода.

Если вы решите переименовать .json-файл каталога, вам нужно будет также изменить название .hash-файла.

Очистка кэша сборок

Перед каждой сборкой каталога рекомендуем очищать кэш предыдущих сборок. Это можно сделать из меню Build -> Clean Build Cache -> All внутри окна групп:

image.png

    Импорт Live2D-моделей

    В модах можно использовать кастомные Live2D-модели.

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

    Требования

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

    Введение

    Для наглядности в данной статье будет описан процесс импорта модели в игру на примере спрайта второстепенного персонажа из старой демо-версии игры.

    Вы можете скачать архив с исходниками по этой ссылке.
    Ссылка на архив с финальным результатом расположена в конце статьи.

    Импорт модели в Unity

    Чтобы импортировать модель в Unity-проект, достаточно поместить её исходники внутрь папки Assets (или в любую её подпапку) — Live2D SDK импортирует модель и сгенерирует для неё префаб, а также контроллер анимации.

    Распакуйте содержимое архива с исходниками спрайта в папку Assets вашего проекта. После того, как Live2D SDK закончит процесс импорта (он запустится автоматически при открытии окна редактора) — внутри папки с исходниками появится префаб, а также несколько вспомогательных ассетов:

    image.png

    Для всех .motion3-файлов внутри папки anim также были сгенерированы анимационные файлы, поддерживаемые Unity:

    image.png

    Откройте файл Kyo.prefab в редакторе — вы увидите импортированную модель:

    image.png

    Справа в окне Inspector будут отображаться настройки различных компонентов Live2D SDK, включая анимируемые параметры нашей модели (компонент Cubism Parameters Inspector):

    image.png

    Если модель не отображается после открытия префаба, попробуйте нажать кнопку Reset внутри Cubism Parameters Inspector (или просто измените значение какого-либо параметра). Также возможно, что модель просто не в фокусе камеры - нажмите F, чтобы сфокусировать камеру.

    Если же модель отображается некорректно — попробуйте в компоненте Cubism Render Controller во вкладке Sorting выставить параметр Mode в Back To Front Order.

    Первое, что нужно сделать — прицепить сгенерированный контроллер анимации к компоненту Animator — просто перетащите его в соответствующие поле:

    Сохраните изменения (если у вас отключено автосохранение) и закройте префаб.

    Удаление исходников

    Очень важно после успешного импорта удалить исходники из проекта. На это есть две причины:

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

    Удалите все .moc3, .model3.json и .motion3 файлы из проекта после завершения процесса импорта модели. НЕ удаляйте текстуры — они используются в префабе.

    Анимации

    Откройте любую сцену в редакторе и перетащите на неё префаб импортированной модели:

    image.png

    Выберите модель в иерархии сцены, затем откройте окно Animator (Window -> Animation -> Animator).

    Вы увидите стандартный шаблон контроллера с базовым слоем:

    image.png

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

    Мы можем сделать анимации вручную — создадим их для рук.

    Переименуйте слой Base Layer в Hands (нужно кликнуть на название слоя), нажмите на шестерёнку справа и убедитесь, что параметр Weight у слоя равен единице:

    image.png
    При создании новых слоёв убедитесь, что значение Weight не равно нулю, иначе анимации на слое никак не будут воздействовать на модель в игре.

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

     Затем создайте на нём новый стейт и назовите его hands1:

    image.png

    Т.к. это единственный стейт на слое, он будет проигрываться по умолчанию при появлении модели на сцене. Создайте второй стейт под второе положение рук — hands2:

    image.png

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

    Откройте папку anim в папке с моделью и найдите там две сгенерированные анимации:

    Это переходные анимации для различных положений рук. Первая — переход из 1 положения во 2, вторая — из 2 в 1. Перетащите оба этих файла на слой Hands, к созданным ранее стейтам:

    image.png

    В отличии от созданных вручную стейтов hands1/hands2, этим стейтам автоматически присвоились анимации. Вы можете увидеть их в инспекторе, в параметре Motion, кликнув по стейту:

    image.png

    Теперь мы можем сделать переходы между 2-мя положениями рук, которые будут проигрываться, когда модель меняет hands1 на hands2 и наоборот.

    Это можно сделать двумя способами:

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

    Переходы

    Реализация переходов при помощи триггеров

    Создайте в параметрах аниматора триггеры, названия которых совпадают с названием стейтов основных положений рук (в данном случае — hands1 и hands2):

    image.png

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

    Переход из hands1 в hands2 активирует триггер hands2, из hands2 в hands1 — триггер hands1. Оба перехода происходят через стейты с анимациями смены положения рук.

    Также снимите чекбокс Has Exit Time у переходов из основных стейтов и поставьте Transition Duration 0:

    image.png

    image.png

     Предупреждение выводится, т.к. у основных стейтов пока что нет анимаций — мы скоро сделаем их.

    У переходов на основные стейты поставьте значение Exit Time на 1 и Transition Duration на 0:   

    image.png

    image.png

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

    Реализация переходов при помощи упрощённой системы

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

    image.png
    Так выглядит слой Head у спрайта himitsu_front

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

    Суть заключается в том, что стейты, которые должны проигрываться при переходах между основными стейтами (положениями рук hands1 и hands2 в нашем случае), называются определённым образом, используя достаточно простой синтаксис:

    стейт_из_которого_переход | стейт_в_который_переход

    Т.е. два стейта — "Стейт A" — из которого нужно перейти — и "Стейт Б" — в который нужно перейти, разделяются символом |

    Создадим такие переходы для наших положений рук. Сейчас у нас есть следующее:

    image.png

    Переименуйте hands1-2 в hands1 | hands2, а hands2-1 в hands2 | hands1:

    image.png

    И всё! Никаких триггеров, стрелочек переходов и прочих настроек. Игра автоматически будет проигрывать наши анимации при смене положений рук. Данный способ очень удобен, если у вас есть анимации переходов между различными состояниями модели и у вас нет необходимости делать сложные системы переходов при помощи аниматора Unity.

    Автоматически переходы

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

    Создание анимаций

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

    Средствами Live2D SDK для Unity создавать анимации крайне проблематично, т.к. окно записи анимаций не будет реагировать на изменение параметров модели (и сама модель не будет реагировать на проигрывание анимаций вне контроллера, который работает только в Play-моде), поэтому для этих целей нами был написан специальный плагин, позволяющий анимировать Live2D-модели внутри Unity.

    Скачайте и импортируйте его в проект.

    Если вы скачали готовый проект по ссылке в начале статьи, плагин можно не качать — он идёт в комплекте.

    Выберите модель на иерархии сцены и добавьте к ней компонент CubismPoser. После этого компонент Cubism Parameters Inspector должен исчезнуть, а вместо него, в самом низу, появится новый компонент с теми же параметрами:

    image.png

    Анимации для положений рук

    Сделаем анимации для основных положений рук - hands1 и hands2.

    Выберите модель на иерархии сцены, затем откройте окно Animation (Window -> Animation -> Animation, или Ctrl + 6). Вы увидите окно, в котором будут ключи анимаций-переходов:

    image.png

    Мы можем посмотреть значения параметров в начале и в конце анимации.

    У первого положения рук (hands1) параметр Ruki1 должен быть равен 0, у второго (hands2) — 1.

    Кликните на выпадающий список в левом верхнем углу окна и создайте новый анимационный файл, нажав на Create New Clip...

    Назовите его hands1 и сохраните в папку с остальными анимациями.

    Убедитесь, что на таймлайне установлен 0 кадр:

    image.png

    Далее включите режим записи, выберите в компоненте CubismPoser параметр Ruki1 и установите его значение на 0:

    image.png

    Затем нажмите кнопку Create Keyframes for Selected (активна только в режиме записи). 

    На таймлайне должен появится ключ со значением нашего параметра:

    image.png

    Поздравляю - вы только что создали анимацию для Live2D-модели в Unity (пусть она и состоит только из одного кадра).

    Сделайте то же самое для hands2, установив значение Ruki1 на 1:

    image.png

    Анимации готовы. Теперь осталось только добавить их к соответствующим стейтам в аниматоре (по идее, они должны добавиться сами, если названия стейтов и анимаций совпадают):

    image.png

    image.png

    Готово. Вы сделали полностью функционирующие положения рук для модели, а также переходы между ними. 

    В исходниках модели также лежат анимации переходов ног — вы можете попрактиковаться на них, процесс абсолютно идентичен.

    Эмоции

    В архиве с исходниками нет никакой анимации эмоций, но вы можете попробовать создать свои. Функциональность модели ограничен (всё же, это спрайт из старой демо-версии игры), но у неё есть несколько параметров, отвечающих за эмоции.

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

    Сделаем несколько эмоций для нашего спрайта: создайте в аниматоре новый слой Emotions и переместите его в самый верх:

    image.png

    Далее создадим несколько анимационных файлов:

    normal

    Обычное (стандартное) выражение лица персонажа, которое будет активно по умолчанию. Выделяем все необходимые параметры, не меняя их значений, и создаём новый файл анимации с ключами:

    image.png

    sad

    image.png

    grin

    image.png

    Для всех созданных анимаций в аниматоре были автоматически проставлены одноимённые стейты — по умолчанию они создаются на самом верхнем (первом) слое:

    image.png

    Нам не нужно ничего менять — для смены эмоций в игре достаточно автоматических переходов.

    Дыхание и моргание

    Дыхание и моргание реализуются при помощи стандартных компонентов Live2D SDK:

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

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

    Дыхание

    Добавим нашей модели анимацию дыхания.

    Откройте префаб и добавьте к нему компонент Cubism Harmonic Motion Controller, значение Blend Mode установите в Override:

    image.png

    Далее в иерархии модели внутри Parameters найдите объект Dihanie и добавьте к нему компонент Cubism Harmonic Motion Parameter:

    image.png

    Установите параметры следующим образом:

    image.png

    Моргание

    Добавьте к префабу модели два компонента: Cubism Eye Blink Controller и Cubism Auto Eye Blink Input со следующими параметрами:

    image.png

    Далее в иерархии модели внутри Parameters найдите объект GLAZA_otkr и добавьте к нему компонент Cubism Eye Blink Parameter:

    image.png

    Сохраните изменения и закройте префаб.

    Проверка

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

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

    image.png

    Включите Play-мод. Если всё сделано верно, модель должна дышать и моргать:

    Финальный результат

    Архив с моделью, анимациями и двумя контроллерами (kyo.controller — с триггерами, kyo_simple.controller — без) можно скачать здесь.

    Экспорт в игру

    1. Соберите каталог с моделью и всеми необходимыми ассетами. 
    2. Добавьте каталог в ресурсы мода.
    3. Добавьте в ресурсы мода спрайт персонажа, вписав модель, необходимые слои и стейты.

    Если вы всё сделали верно, модель и анимации будут корректно отображаться в игре:

    Исходники Live2D-спрайтов для Unity

    Описание

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

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

    Ссылка

    Вы можете скачать архив с исходниками, кликнув по этой ссылке. Распакуйте содержимое архива внутрь папки Assets вашего проекта.

    Содержимое

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

    Внутри папки anims находятся подпапки, содержащие контроллеры и анимации.

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

    Переводы сценариев

    Строки в сценарии можно переводить на другие языки.

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

    Подготовка сценария

    Первое, что нужно сделать — это подготовить сценарий для перевода.

    Следующие команды сценария поддерживают переводы:

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

    # пример сценария с локализируемыми командами
    text1: "Эти падающие лепестки сакуры..."
    
    menu 
    {
        text2: "Опция 1"
        {
          "..."
        }
    
        text3: "Опция 2"
        {
          "..."
        }
    }

    Здесь text1, text2 и text3 — идентификаторы строк для переводов. Они необязательно должны называться именно так, можно написать любое название (однако оно подчиняется общим правилам составления имён — только латинские буквы, цифры и нижнее подчёркивание), но оно обязательно должно начинаться с буквы.

    Файл перевода

    Переводы для сценариев хранятся в .csv-файлах. 

    Рассмотрим перевод первого дня игрового сценария:

    image.png

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

    Чтобы прописать в строке кавычку (т.е., чтобы она отображалась непосредственно в игре), нужно перед ней поставить символ \ — обратный слэш:

    image.png

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

    После создания файла перевода, вы можете прописать его в resources.yaml.

    Разделитель

    Можно использовать любой разделитель, поддерживаемый .csv-форматом. Однако мы рекомендуем использовать символ ;.

    Примеры

    Вы можете посмотреть, как устроены игровые сценарии и их переводы на этой странице.

    Загрузка мода в Steam Workshop

    Для загрузки вашего мода в Steam Workshop вы можете воспользоваться специальной утилитой, которая расположена в папке Love, Money, Rock'n'Roll_Data\workshop_uploader.

    Утилита доступна под следующие платформы:

    Графический интерфейс

    Или же lmr-workshop-gui(.exe).

    При запуске программы вы увидите меню с двумя кнопками:

    image.png

    Первая создаёт новый мод в Workshop, вторая обновляет существующий.

    В обоих случаях вы увидите одинаковое окно с различными параметрами:

    image.png
    Загрузка нового мода

    image.png
    Обновление существующего мода

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

    uploader_label.gif

    Это также работает и при создании мода — вы можете отключить ненужные поля.

    Чтобы вернуться обратно в меню, кликните по заголовку страницы:

    uploader_goback.gif

    Процесс загрузки/обновления мода

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

    Если клиент Steam не запущен, вы не залогинены или нет соединения с интернетом, появится окно с ошибкой:

    image.png

    После успешной загрузки/обновления будет выведен ID вашего мода, а также ссылка на него:

    image.png

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

    Если вы не принимали со своего аккаунта соглашение подписчика Steam, вы не сможете изменить видимость страницы мода, пока не примите соглашение.

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

    Вы можете изменить настройки видимости вашего мода на странице в мастерской либо через утилиту, обновив мод с указанием настройки видимости.

    Консольный интерфейс

    Если вы предпочитаете взаимодействовать с консолью, то вы можете воспользоваться утилитой lmr-workshop(.exe).

    Список доступных параметров:

      -mode|--mode                    Operating mode. Possible values: create, update
      -id|--id                        The ID of the Steam Workshop item. Used with update mode and --open-item-page.
      -ttl|--title                    Sets a new title for an item
      -dsc|--description              Sets a new description for an item
      -lng|--language                 Sets the language of the title and description that will be set in this item update
      -vsb|--visibility               Sets the visibility of an item. 0 - public, 1 - friends only, 2 - private, 3 -
                                      unlisted
      -ct|--content                   Sets the folder that will be stored as the content for an item
      -pw|--preview                   Sets the primary preview image for the item
      -cn|--change-note               Change note for an item upload
      -joutput|--json-output          Returns all output in JSON
      -owa|--open-workshop-agreement  Opens Steam Workshop Legal Agreement in the Steam Client App
      -oip|--open-item-page           Opens item workshop page in the Steam Client App
      -?|-h|--help                    Show help information.

    Запуск под Linux

    Для работы программы на Linux может потребоваться файл steamclient.so, который является частью SteamCMD. Без этого файла, при попытке загрузить изменения, вы получите сообщение о незапущенном клиенте Steam.

    После установки SteamCMD, найдите указанный файл и поместите его в папку home/%имя_юзера%/.steam/sdk64 (или по тому пути, который требует программа на вашей системе).

    Вы также можете скачать необходимый файл отдельно.

    Запуск под macOS

    Если программа не запускается, ознакомьтесь с данной статьёй.

    Миграция со старой системы модов

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

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

    Чтобы корректно интегрировать сценарии таких модов в новую систему, нужно будет провести несколько изменений.

    Positions

    Числовые положения спрайтов, прописывающиеся в сценарии при помощи ключевого параметра at, были изменены. Теперь координаты рассчитываются относительно центра экрана, в значениях в диапазоне от -1 до 1.

    Чтобы получить корректное значение для новой системы из старых координат, нужно разделить значение X на 640, а Y на 16.85.

    Т.е, если раньше было: 
    show hi at 537 -6.68

    То в новой системе оно будет выглядеть так (значения округлены):
    show hi at 0.84 -0.4

    Sizes

    Размеры тоже изменились. Нормальный (стандартный) размер спрайта теперь равен 1.

    Чтобы получить корректные значения, X и Y нужно разделить на 16.85.

    Было:
    show hi size 9 9

    Стало (значения округлены):
    show hi size 0.53 0.53

    Backdrop

    Раньше, чтобы вывести backdrop-фон без текста, нужно было либо делать дополнительную пустую строку в XML-ассете, либо писать backdrop "".

    В этом больше нет необходимости, текст у команды backdrop необязателен.

    Строчки, вроде backdrop или backdrop bg el, в которых нет текста, теперь являются корректными.

    Баги и обратная связь

    Ниже приведён список багов, о которых известно на данный момент, но которые по тем или иным причинам пока что не были исправлены.

    Если вы обнаружите баг, которого нет в этом списке, пожалуйста, сообщите нам о нём одним из следующих способов:

    Также мы будем признательны за репорты об ошибках и неточностях в документации.

    Известные баги

    Crossfade и fade не работают для внешних звуковых файлов

    Описание

    Треки, загруженные из внешних звуковых файлов, не могут использовать параметры crossfade и fadein/fadeout, если текущий и следующий трек — один и тот же файл (например, в случаях, когда трек должен зацикливаться с одним из вышеуказанных параметров).

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

    Временное решение

    Треки можно поместить в бандл (каталог) — в таком случае все функции будут работать корректно.