Manuals
Manuals




This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English

Нативні розширення

Якщо вам потрібна власна взаємодія із зовнішнім програмним або апаратним забезпеченням на низькому рівні, де можливостей Lua недостатньо, Defold SDK дає змогу писати розширення рушія мовами C, C++, C#, Objective-C, Java або JavaScript залежно від цільової платформи. Типові випадки використання нативних розширень (native extensions):

  • Взаємодія з певним апаратним забезпеченням, наприклад із камерою мобільного телефона.
  • Взаємодія із зовнішніми низькорівневими API, наприклад API рекламних мереж, які не підтримують взаємодію через мережеві API, де можна було б використати Luasocket.
  • Високопродуктивні обчислення й обробка даних.

Підтримка C# є експериментальною й призначена для нативних розширень, а не для компонентів-скриптів (script components) Defold. Вона використовує .NET 9 NativeAOT для створення статичної бібліотеки; додайте файли вихідного коду .cs до папки src розширення, і сервіс збирання згенерує файл проєкту. Підтримка цільових платформ залежить від поточних можливостей NativeAOT і сервісу збирання. Актуальний порядок роботи й перевірену конфігурацію наведено в офіційному прикладі мов для нативних розширень.

Сервер збирання

Defold дає змогу почати роботу з нативними розширеннями без налаштування завдяки хмарному збиранню. Будь-яке нативне розширення, розроблене й додане до ігрового проєкту безпосередньо або через бібліотечний проєкт, стає частиною звичайного вмісту проєкту. Не потрібно збирати спеціальні версії рушія й розповсюджувати їх серед учасників команди: це відбувається автоматично — кожен учасник команди, який збирає та запускає проєкт, отримає виконуваний файл рушія для цього проєкту з усіма вбудованими нативними розширеннями.

Хмарне збирання

Defold надає хмарний сервер збирання безкоштовно й без обмежень використання. Сервер розміщено в Європі, а URL, на який надсилається нативний код, налаштовується у вікні Editor Preferences або за допомогою параметра командного рядка --build-server для bob. Якщо ви хочете налаштувати власний сервер, дотримуйтеся цих інструкцій.

Структура проєкту

Щоб створити нове розширення, створіть папку в корені проєкту. Ця папка міститиме всі налаштування, вихідний код, бібліотеки й ресурси, пов’язані з розширенням. Засіб збирання розширень розпізнає структуру папок і збирає всі файли вихідного коду та бібліотеки.

 myextension/
 │
 ├── ext.manifest
 │
 ├── src/
 │
 ├── include/
 │
 ├── lib/
 │   └──[platforms]
 │
 ├── manifests/
 │   └──[platforms]
 │
 └── res/
     └──[platforms]

ext.manifest
Папка розширення обов’язково має містити файл ext.manifest. Це файл конфігурації з прапорцями й макровизначеннями, які використовуються під час збирання окремого розширення. Опис формату файлу наведено в посібнику з маніфесту розширення.
src
Ця папка має містити всі файли вихідного коду.
include
Ця необов’язкова папка містить файли для включення.
lib
Ця необов’язкова папка містить скомпільовані бібліотеки, від яких залежить розширення. Файли бібліотек слід розміщувати в підпапках із назвами у форматі platform або architecture-platform, залежно від того, які архітектури підтримують ваші бібліотеки.

Підтримувані платформи: ios, android, osx, win32, linux, web.

Підтримувані пари arc-platform: arm64-ios, x86_64-ios, armv7-android, arm64-android, x86_64-android, arm64-osx, x86_64-osx, x86-win32, x86_64-win32, arm64-linux, x86_64-linux, wasm-web і wasm_pthread-web.

manifests
Ця необов’язкова папка містить додаткові файли, що використовуються під час збирання або пакування. Докладніше див. нижче.
res
Ця необов’язкова папка містить додаткові ресурси, від яких залежить розширення. Файли ресурсів слід розміщувати в підпапках із назвами у форматі platform або architecture-platform, як і підпапки lib. Також допускається підпапка common, яка містить файли ресурсів, спільні для всіх платформ.

Файли маніфестів

Необов’язкова папка manifests розширення містить додаткові файли, що використовуються під час збирання й пакування. Файли слід розміщувати в підпапках із назвами у форматі platform:

  • android — у цій папці можна розмістити файл фрагмента маніфесту, який буде об’єднано з маніфестом основного застосунку (як описано тут).
    • Папка також може містити файл build.gradle із залежностями, які оброблятиме Gradle.
    • Крім того, папка може містити довільну кількість файлів ProGuard, зокрема жодного (експериментальна можливість).
  • ios — у цій папці можна розмістити файл фрагмента маніфесту, який буде об’єднано з маніфестом основного застосунку (як описано тут).
  • osx — у цій папці можна розмістити файл фрагмента маніфесту, який буде об’єднано з маніфестом основного застосунку (як описано тут).
  • web — у цій папці можна розмістити файл фрагмента маніфесту, який буде об’єднано з маніфестом основного застосунку (як описано тут).

Поширення розширення

Розширення обробляються так само, як будь-які інші ресурси проєкту, і їх можна поширювати так само. Якщо папку нативного розширення додано як папку бібліотеки, нею можна поділитися, щоб інші могли використовувати її як залежність проєкту. Докладніше див. у посібнику з бібліотечних проєктів.

Простий приклад розширення

Створімо дуже просте розширення. Спочатку створимо папку myextension у корені проєкту й додамо файл ext.manifest із назвою розширення MyExtension. Зауважте, що назва є символом C++ і має збігатися з першим аргументом DM_DECLARE_EXTENSION (див. нижче).

Маніфест

# C++ symbol in your extension
name: "MyExtension"

Розширення складається з одного файлу C++, myextension.cpp, який створюється в папці src.

Файл C++

Файл вихідного коду розширення містить такий код:

// myextension.cpp
// Extension lib defines
#define LIB_NAME "MyExtension"
#define MODULE_NAME "myextension"

// include the Defold SDK
#include <dmsdk/sdk.h>

static int Reverse(lua_State* L)
{
    // The number of expected items to be on the Lua stack
    // once this struct goes out of scope
    DM_LUA_STACK_CHECK(L, 1);

    // Check and get parameter string from stack
    char* str = (char*)luaL_checkstring(L, 1);

    // Reverse the string
    int len = strlen(str);
    for(int i = 0; i < len / 2; i++) {
        const char a = str[i];
        const char b = str[len - i - 1];
        str[i] = b;
        str[len - i - 1] = a;
    }

    // Put the reverse string on the stack
    lua_pushstring(L, str);

    // Return 1 item
    return 1;
}

// Functions exposed to Lua
static const luaL_reg Module_methods[] =
{
    {"reverse", Reverse},
    {0, 0}
};

static void LuaInit(lua_State* L)
{
    int top = lua_gettop(L);

    // Register lua names
    luaL_register(L, MODULE_NAME, Module_methods);

    lua_pop(L, 1);
    assert(top == lua_gettop(L));
}

dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params)
{
    return dmExtension::RESULT_OK;
}

dmExtension::Result InitializeMyExtension(dmExtension::Params* params)
{
    // Init Lua
    LuaInit(params->m_L);
    printf("Registered %s Extension\n", MODULE_NAME);
    return dmExtension::RESULT_OK;
}

dmExtension::Result AppFinalizeMyExtension(dmExtension::AppParams* params)
{
    return dmExtension::RESULT_OK;
}

dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
{
    return dmExtension::RESULT_OK;
}


// Defold SDK uses a macro for setting up extension entry points:
//
// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)

// MyExtension is the C++ symbol that holds all relevant extension data.
// It must match the name field in the `ext.manifest`
DM_DECLARE_EXTENSION(MyExtension, LIB_NAME, AppInitializeMyExtension, AppFinalizeMyExtension, InitializeMyExtension, 0, 0, FinalizeMyExtension)

Зверніть увагу на макрос DM_DECLARE_EXTENSION, який використовується для оголошення різних точок входу в код розширення. Перший аргумент symbol має збігатися з назвою, зазначеною в ext.manifest. У цьому простому прикладі точки входу update і on_event не потрібні, тому у відповідні аргументи макросу передається 0.

Тепер залишається лише зібрати проєкт (Project ▸ Build). Розширення буде надіслано до засобу збирання розширень, який створить власну версію рушія з новим розширенням. Якщо під час збирання виникнуть помилки, з’явиться діалогове вікно з помилками збирання.

Щоб перевірити розширення, створіть ігровий об’єкт (game object) і додайте компонент-скрипт із тестовим кодом:

local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
local reverse_s = myextension.reverse(s)
print(reverse_s) --> ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba

Ось і все! Ми створили повністю працездатне нативне розширення.

Життєвий цикл розширення

Як ми бачили вище, макрос DM_DECLARE_EXTENSION використовується для оголошення різних точок входу в код розширення:

DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)

Точки входу дають змогу виконувати код на різних етапах життєвого циклу розширення:

  • Запуск рушія
    • Запускаються системи рушія
    • app_init розширення
    • init розширення — усі API Defold уже ініціалізовано. Це рекомендований етап життєвого циклу розширення для створення прив’язок Lua до коду розширення.
    • Ініціалізація скриптів — викликається функція init() файлів скриптів.
  • Цикл рушія
    • Оновлення рушія
      • update розширення
      • Оновлення скриптів — викликається функція update() файлів скриптів.
    • Події рушія (згортання та розгортання вікна тощо)
      • on_event розширення
  • Завершення роботи рушія (або перезапуск)
    • Завершення роботи скриптів — викликається функція final() файлів скриптів.
    • final розширення
    • app_final розширення

Визначені ідентифікатори платформ

Засіб збирання визначає такі ідентифікатори на відповідних платформах:

  • DM_PLATFORM_WINDOWS
  • DM_PLATFORM_OSX
  • DM_PLATFORM_IOS
  • DM_PLATFORM_ANDROID
  • DM_PLATFORM_LINUX
  • DM_PLATFORM_HTML5

Журнали сервера збирання

Журнали сервера збирання доступні, коли проєкт використовує нативні розширення. Під час збирання проєкту журнал сервера збирання (log.txt) завантажується разом із власною версією рушія та зберігається у файлі .internal/%platform%/build.zip, а також розпаковується до папки збирання вашого проєкту.

Приклади розширень

Портал ресурсів Defold також містить кілька нативних розширень.