Unreal EngineMiddleTechnical

Что такое Data Asset в Unreal Engine и когда использовать его вместо struct?

Data Asset — это UObject-наследник с UPROPERTY-полями, сохраняемый как отдельный asset в контент-браузере; struct не имеет identity, не может иметь ссылки и не редактируется как самостоятельный файл.

Что такое Data Asset

UDataAsset — базовый класс Unreal Engine для объектов-данных, которые сохраняются как отдельные .uasset-файлы в контент-браузере. Они поддерживают стандартный UE-пайплайн: ссылки через TSoftObjectPtr, асинхронная загрузка через Asset Manager, Blueprint-редактирование и наследование.

Когда использовать Data Asset

  • Конфигурация оружия, предметов, NPC — данные, которые дизайнеры правят независимо.
  • Нужна ссылка на конкретный экземпляр (Asset Reference) — например, иконка предмета, звук, скелетная меш.
  • Данные должны быть загружены асинхронно через UAssetManager.
  • Нужно наследование: UWeaponDataURifleData.

Когда использовать struct

  • Данные — только значения, без asset-ссылок и идентификатора.
  • Передача параметров внутри одной системы (не нужно сохранять в контенте).
  • Встроенные данные внутри другого объекта (поле в DataTable, параметр функции).

Создание Data Asset в C++

// WeaponData.h
#pragma once
#include "Engine/DataAsset.h"
#include "WeaponData.generated.h"

UCLASS(BlueprintType)
class MYGAME_API UWeaponData : public UPrimaryDataAsset
{
    GENERATED_BODY()
public:
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Stats")
    float Damage = 25.f;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Stats")
    float FireRate = 0.1f;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Visuals")
    TSoftObjectPtr<USkeletalMesh> Mesh;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Audio")
    TSoftObjectPtr<USoundBase> FireSound;

    // Обязательно для Asset Manager
    virtual FPrimaryAssetId GetPrimaryAssetId() const override
    {
        return FPrimaryAssetId(TEXT("WeaponData"), GetFName());
    }
};

Регистрация в Asset Manager (DefaultGame.ini)

[/Script/Engine.AssetManagerSettings]
+PrimaryAssetTypesToScan=(
    PrimaryAssetType="WeaponData",
    AssetBaseClass="/Script/MyGame.WeaponData",
    bHasBlueprintClasses=False,
    Directories=((Path="/Game/Data/Weapons"))
)

Асинхронная загрузка через Asset Manager

UAssetManager& AM = UAssetManager::Get();
FPrimaryAssetId WeaponId(TEXT("WeaponData"), TEXT("Rifle_AK47"));

TArray<FName> Bundles;
FStreamableDelegate Delegate = FStreamableDelegate::CreateUObject(
    this, &AMyCharacter::OnWeaponLoaded, WeaponId);
AM.LoadPrimaryAsset(WeaponId, Bundles, Delegate);

void AMyCharacter::OnWeaponLoaded(FPrimaryAssetId AssetId)
{
    UWeaponData* Data = Cast<UWeaponData>(
        UAssetManager::Get().GetPrimaryAssetObject(AssetId));
    if (Data) { /* применяем данные */ }
}

Подводные камни

  • UDataAsset vs UPrimaryDataAsset: только UPrimaryDataAsset поддерживает Asset Manager и bundle-загрузку; UDataAsset — просто UObject, без GetPrimaryAssetId().
  • Hard reference вместо TSoftObjectPtr: прямая ссылка USkeletalMesh* в Data Asset грузит меш сразу при загрузке самого asset, раздувая память.
  • Отсутствие PrimaryAssetType в DefaultGame.ini: Asset Manager не найдёт asset, метод GetPrimaryAssetId() вернёт Invalid.
  • Изменение имени класса: переименование C++-класса Data Asset разрывает все ссылки в контенте; нужен UObjectRedirector или ручное переподключение.
  • CDO и изменяемые дефолты: Data Asset — не CDO; если несколько систем читают один asset и кто-то изменяет его поля в рантайме, изменения видны всем.
  • DataTable vs DataAsset: для табличных данных (сотни строк) DataTable + struct эффективнее, чем сотни отдельных Data Asset файлов.

Common mistakes

  • Объяснять Data Asset только по синтаксису, без жизненного цикла и стоимости.
  • Игнорировать ошибки, null/empty состояния, порядок инициализации или режим сборки.
  • Давать пример, который работает в демо, но ломается при изменении владельца ресурса.
  • Использовать макросы или specifier-и наугад и забывать про UObject GC.

What the interviewer is testing

  • Кандидат формулирует точную модель для Data Asset, а не только определение.
  • Пример компилируем, безопасен по lifetime и соответствует версии технологии.
  • Названы trade-off, ограничения и диагностируемые симптомы ошибки.
  • Понимает границу между C++ кодом, runtime/framework metadata и editor/UI слоем.

Sources

Related topics