Skip to content

Глава 2.4: Ваш первый мод — минимально жизнеспособный

Главная | << Назад: mod.cpp и Workshop | Минимально жизнеспособный мод | Далее: Организация файлов >>


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


Содержание


Что вам нужно

  • Установленная игра DayZ (розничная версия или DayZ Tools/Diag)
  • Текстовый редактор (VS Code, Notepad++ или любой текстовый редактор)
  • Установленные DayZ Tools (для упаковки PBO) — ИЛИ вы можете тестировать без упаковки (см. Шаг 5)

Цель

Мы создадим мод под названием HelloMod, который:

  1. Загружается в DayZ без ошибок
  2. Выводит "[HelloMod] Mission started!" в скриптовый лог
  3. Использует правильную стандартную структуру

Это DayZ-эквивалент «Hello World».


Шаг 1: Создание структуры каталогов

Создайте следующие папки и файлы. Вам нужно ровно 3 файла:

HelloMod/
  mod.cpp
  Scripts/
    config.cpp
    5_Mission/
      HelloMod/
        HelloMission.c

Это полная структура. Давайте создадим каждый файл.


Шаг 2: Создание mod.cpp

Создайте HelloMod/mod.cpp с таким содержимым:

cpp
name = "Hello Mod";
author = "YourName";
version = "1.0";
overview = "My first DayZ mod - prints a message on mission start.";

Это минимальные метаданные. Лаунчер DayZ покажет «Hello Mod» в списке модов.


Шаг 3: Создание config.cpp

Создайте HelloMod/Scripts/config.cpp с таким содержимым:

cpp
class CfgPatches
{
    class HelloMod_Scripts
    {
        units[] = {};
        weapons[] = {};
        requiredVersion = 0.1;
        requiredAddons[] =
        {
            "DZ_Data"
        };
    };
};

class CfgMods
{
    class HelloMod
    {
        dir = "HelloMod";
        name = "Hello Mod";
        author = "YourName";
        type = "mod";

        dependencies[] = { "Mission" };

        class defs
        {
            class missionScriptModule
            {
                value = "";
                files[] = { "HelloMod/Scripts/5_Mission" };
            };
        };
    };
};

Разберём, что делает каждая часть:

  • CfgPatches объявляет мод движку. requiredAddons указывает, что мы зависим от DZ_Data (базовые данные ванильного DayZ), что гарантирует загрузку после базовой игры.
  • CfgMods сообщает движку, где находятся наши скрипты. Мы используем только 5_Mission, потому что именно там доступны хуки жизненного цикла миссий.
  • dependencies перечисляет "Mission", потому что наш код подключается к скриптовому модулю миссий.

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

Создайте HelloMod/Scripts/5_Mission/HelloMod/HelloMission.c с таким содержимым:

c
modded class MissionServer
{
    override void OnInit()
    {
        super.OnInit();
        Print("[HelloMod] Mission started! Server is running.");
    }
};

modded class MissionGameplay
{
    override void OnInit()
    {
        super.OnInit();
        Print("[HelloMod] Mission started! Client is running.");
    }
};

Что это делает:

  • modded class MissionServer расширяет ванильный класс серверной миссии. Когда сервер запускает миссию, вызывается OnInit() и выводится наше сообщение.
  • modded class MissionGameplay делает то же самое для клиентской стороны.
  • super.OnInit() вызывает оригинальную (ванильную) реализацию первой — это критически важно. Никогда не пропускайте этот вызов.
  • Print() записывает в файл скриптового лога DayZ.

Шаг 5: Сборка и тестирование

У вас два варианта тестирования:

Вариант A: File Patching (без PBO — только для разработки)

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

  1. Поместите вашу папку HelloMod/ в каталог установки DayZ (или используйте диск P: с Workbench)
  2. Запустите DayZ с параметром -filePatching и загрузите ваш мод:
DayZDiag_x64.exe -mod=HelloMod -filePatching

Это загружает скрипты напрямую из папки без упаковки в PBO.

Вариант B: Упаковка в PBO (обязательно для распространения)

Для публикации в Workshop или развёртывания на сервере нужна упаковка в PBO:

  1. Откройте DayZ Tools (из Steam)
  2. Откройте Addon Builder
  3. Установите исходный каталог на HelloMod/Scripts/
  4. Установите выходной путь на @HelloMod/Addons/HelloMod_Scripts.pbo
  5. Нажмите Pack

Или используйте упаковщик командной строки вроде PBOConsole:

PBOConsole.exe -pack HelloMod/Scripts @HelloMod/Addons/HelloMod_Scripts.pbo

Разместите mod.cpp рядом с папкой Addons/:

@HelloMod/
  mod.cpp
  Addons/
    HelloMod_Scripts.pbo

Затем запустите DayZ:

DayZDiag_x64.exe -mod=@HelloMod

Шаг 6: Проверка работоспособности

Поиск скриптового лога

DayZ записывает вывод скриптов в файлы логов в каталоге вашего профиля:

Windows: C:\Users\YourName\AppData\Local\DayZ\

Ищите самый свежий .RPT или .log файл. Скриптовый лог обычно называется:

script_<дата>_<время>.log

Что искать

Откройте файл лога и найдите [HelloMod]. Вы должны увидеть:

[HelloMod] Mission started! Server is running.

или (если вы подключились как клиент):

[HelloMod] Mission started! Client is running.

Если вы видите это сообщение — поздравляем, ваш мод работает.

Если вы видите ошибки

Если лог содержит строки, начинающиеся с SCRIPT (E):, что-то пошло не так. Смотрите раздел Устранение неполадок ниже.


Что произошло

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

1. Движок запускается, читает файлы config.cpp из всех PBO
2. CfgPatches "HelloMod_Scripts" зарегистрирован
   --> requiredAddons гарантирует загрузку после DZ_Data
3. CfgMods "HelloMod" зарегистрирован
   --> Движок знает о пути missionScriptModule
4. Движок компилирует скрипты 5_Mission всех модов
   --> HelloMission.c скомпилирован
   --> "modded class MissionServer" патчит ванильный класс
5. Сервер запускает миссию
   --> Вызывается MissionServer.OnInit()
   --> Ваш override запускается, сначала вызывая super.OnInit()
   --> Print() записывает в скриптовый лог
6. Клиент подключается и загружается
   --> Вызывается MissionGameplay.OnInit()
   --> Ваш override запускается
   --> Print() записывает в клиентский лог

Ключевое слово modded — ключевой механизм. Оно говорит движку «возьми существующий класс и добавь мои изменения поверх». Так каждый мод DayZ интегрируется с ванильным кодом.


Следующие шаги

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

Добавление слоя 3_Game

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

HelloMod/
  Scripts/
    config.cpp              <-- Добавить запись gameScriptModule
    3_Game/
      HelloMod/
        HelloConfig.c       <-- Класс конфигурации
    5_Mission/
      HelloMod/
        HelloMission.c      <-- Существующий файл

Обновите config.cpp, чтобы включить новый слой:

cpp
dependencies[] = { "Game", "Mission" };

class defs
{
    class gameScriptModule
    {
        value = "";
        files[] = { "HelloMod/Scripts/3_Game" };
    };
    class missionScriptModule
    {
        value = "";
        files[] = { "HelloMod/Scripts/5_Mission" };
    };
};

Добавление слоя 4_World

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

HelloMod/
  Scripts/
    config.cpp              <-- Добавить запись worldScriptModule
    3_Game/
      HelloMod/
        HelloConfig.c
    4_World/
      HelloMod/
        HelloManager.c      <-- Логика, связанная с миром
    5_Mission/
      HelloMod/
        HelloMission.c

Добавление UI

Создайте простую игровую панель (рассматривается в Части 3 этого руководства):

HelloMod/
  GUI/
    layouts/
      hello_panel.layout    <-- Файл компоновки UI
  Scripts/
    5_Mission/
      HelloMod/
        HelloPanel.c        <-- Скрипт UI

Добавление пользовательского предмета

Определите предмет в Data/config.cpp и создайте его скриптовое поведение в 4_World:

HelloMod/
  Data/
    config.cpp              <-- CfgVehicles с определением предмета
    Models/
      hello_item.p3d        <-- 3D-модель
  Scripts/
    4_World/
      HelloMod/
        HelloItem.c         <-- Скрипт поведения предмета

Зависимость от фреймворка

Если вы хотите использовать возможности Community Framework (CF), добавьте зависимость:

cpp
// В config.cpp
requiredAddons[] = { "DZ_Data", "JM_CF_Scripts" };

Устранение неполадок

«Addon HelloMod_Scripts requires addon DZ_Data which is not loaded»

Ваш requiredAddons ссылается на аддон, который отсутствует. Убедитесь, что DZ_Data написан правильно и базовая игра DayZ загружена.

Нет вывода в лог (мод, похоже, не загрузился)

Проверьте по порядку:

  1. Указан ли мод в параметре запуска? Убедитесь, что -mod=HelloMod или -mod=@HelloMod есть в вашей команде запуска.
  2. Находится ли config.cpp в правильном месте? Он должен быть в корне PBO (или в корне папки Scripts/ при использовании file-patching).
  3. Правильны ли пути к скриптам? Пути files[] в config.cpp должны совпадать с реальной структурой каталогов. "HelloMod/Scripts/5_Mission" означает, что движок ищет именно этот путь.
  4. Есть ли класс CfgPatches? Без него PBO игнорируется.

SCRIPT (E): Undefined variable / Undefined type

Ваш код ссылается на то, что не существует на этом слое. Частые причины:

  • Ссылка на PlayerBase из 3_Game (он определён в 4_World)
  • Опечатка в имени класса или переменной
  • Пропущенный вызов super.OnInit() (вызывает каскадные сбои)

SCRIPT (E): Member not found

Метод или свойство, которое вы вызываете, не существует в этом классе. Перепроверьте ванильный API. Частая ошибка: вызов методов из более новой версии DayZ при запуске более старой.

Мод загружается, но скрипт не выполняется

  • Проверьте, что ваш .c файл находится внутри каталога, указанного в files[]
  • Убедитесь, что файл имеет расширение .c (не .txt или .cs)
  • Проверьте, что имя modded class точно совпадает с ванильным классом (с учётом регистра)

Ошибки упаковки PBO

  • Убедитесь, что config.cpp находится на корневом уровне внутри PBO
  • Пути внутри PBO используют прямые слеши (/), а не обратные
  • Убедитесь, что в папке Scripts нет бинарных файлов (только .c и .cpp)

Лучшие практики

  • Всегда вызывайте super.OnInit() перед вашим кодом в модифицированных классах миссий — пропуск ломает инициализацию других модов.
  • Используйте уникальный префикс в сообщениях Print() (например, [HelloMod]), чтобы можно было быстро найти по логам.
  • Начинайте только с 5_Mission. Добавляйте слои 3_Game и 4_World постепенно по мере роста мода.
  • Используйте -filePatching во время разработки, чтобы не переупаковывать PBO при каждом изменении.
  • Держите первый мод в пределах 3 файлов, пока он не заработает, затем расширяйте. Отладка минимальной структуры гораздо проще.

Теория и практика

КонцепцияТеорияРеальность
Print() выводит в логСообщения появляются в скриптовом логеВывод идёт в файл .RPT, а не в отдельный скриптовый лог. На выделенных серверах проверяйте серверный RPT в папке профиля
-filePatching загружает распакованные файлыНеупакованные моды работают мгновенноНекоторые ассеты (модели, текстуры) всё равно требуют упаковки в PBO; скрипты работают распакованными, но файлы .layout могут не загружаться из неупакованных папок на всех конфигурациях
modded class патчит ванильныйВаш override заменяет оригиналНесколько модов могут выполнить modded class одного класса; они выстраиваются в цепочку по порядку загрузки. Если один пропускает super.OnInit(), все последующие моды ломаются
DZ_Data — единственная нужная зависимостьМинимальный requiredAddonsРаботает для чисто скриптовых модов, но если вы ссылаетесь на ванильный класс оружия/предмета, вам также нужен DZ_Scripts или конкретный ванильный PBO
Трёх файлов достаточноМод загружается с mod.cpp + config.cpp + один .c файлВерно для чисто скриптового мода, но добавление предметов или UI требует дополнительных PBO (Data, GUI)

Полный листинг файлов

Для справки — все три файла полностью:

HelloMod/mod.cpp

cpp
name = "Hello Mod";
author = "YourName";
version = "1.0";
overview = "My first DayZ mod - prints a message on mission start.";

HelloMod/Scripts/config.cpp

cpp
class CfgPatches
{
    class HelloMod_Scripts
    {
        units[] = {};
        weapons[] = {};
        requiredVersion = 0.1;
        requiredAddons[] =
        {
            "DZ_Data"
        };
    };
};

class CfgMods
{
    class HelloMod
    {
        dir = "HelloMod";
        name = "Hello Mod";
        author = "YourName";
        type = "mod";

        dependencies[] = { "Mission" };

        class defs
        {
            class missionScriptModule
            {
                value = "";
                files[] = { "HelloMod/Scripts/5_Mission" };
            };
        };
    };
};

HelloMod/Scripts/5_Mission/HelloMod/HelloMission.c

c
modded class MissionServer
{
    override void OnInit()
    {
        super.OnInit();
        Print("[HelloMod] Mission started! Server is running.");
    }
};

modded class MissionGameplay
{
    override void OnInit()
    {
        super.OnInit();
        Print("[HelloMod] Mission started! Client is running.");
    }
};

Предыдущая: Глава 2.3: mod.cpp и WorkshopСледующая: Глава 2.5: Лучшие практики организации файлов

Released under CC BY-SA 4.0 | Code examples under MIT License