mcpField
U
ue-data-assets-tables

ue-data-assets-tables

github.com/quodsoler開発4191.2k 回インストール4 週間前に更新
リポジトリ

ue-data-assets-tables について

UE 5.8 の開発者向けに、デザイナーが作成するゲームデータとアセット読み込みを扱うスキルです。データコンテナの選択から非同期読み込み、実行時レジストリまでを説明します。

主な機能

  1. 01データコンテナの選択
  2. 02データアセットとテーブル
  3. 03ソフト参照とハード参照
  4. 04非同期アセット読み込み
  5. 05Asset Manager とクックルール
  6. 06レジストリ検索と設定

活用シーン

  1. 01ゲームデータのコンテナ選定
  2. 02アセットの非同期読み込み
  3. 03読み込まずにアセットを検索
  4. 04実行時に複数ソースの行を共有

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/quodsoler/unreal-engine-skills --skill ue-data-assets-tables

インストール後、Claude Code で/ue-data-assets-tablesを入力して読み込まれたか確認します。

同梱ファイルreferences/asset-loading-patterns.mdreferences/data-driven-design.md

詳細

UE データアセットとテーブル

対象エンジン:UE 5.8。以下の API は 5.8 のヘッダーで確認済みです。古い形式は「非推奨 — 使用しないでください」に記載しています。

このスキルでは、デザイナーが作成するゲームデータと、それをメモリに読み込むための方法を扱います。対象は、UDataAsset/UPrimaryDataAsset、UDataTable/UCurveTable、ソフト参照、FStreamableManager、UAssetManager のプライマリアセットとクックルール、IAssetRegistry クエリ、DataRegistry プラグイン、UDeveloperSettings です。Build.cs のモジュールは、データアセット、テーブル、ソフトポインターには Engine と CoreUObject、レジストリクエリには AssetRegistry、設定クラスには DeveloperSettings、データレジストリには DataRegistry です。詳しい解説は、アセット読み込みのパターンとデータ駆動設計のパターンを参照してください。

コンテキスト

.agents/ue-project-context.md が存在する場合は、読み込んでください(モジュール名、規約、有効なプラグイン、カスタムの UAssetManager サブクラス、登録済みのプライマリアセットタイプ)。ファイルがなくても作業を中断しないでください。

依頼内容とコードベースから該当する領域を特定してください。解釈が複数あり、それぞれで異なるコードになる場合に限り、質問してください。

依頼内容…参照先
ゲームデータのコンテナーの選択データコンテナーの選択
UDataAsset、UPrimaryDataAsset、アセットバンドルデータアセット
行構造体、CSV/JSON インポート、FindRowデータテーブル
カーブ、テーブルの合成カーブテーブルとコンポジットテーブル
TSoftObjectPtr、FSoftObjectPath、メモリ予算参照:ハード参照とソフト参照
非同期読み込み、ハンドル、優先度非同期読み込み
FPrimaryAssetId、スキャン、バンドルの状態アセットマネージャー
クック、チャンク化、PrimaryAssetTypesToScanクックルール
アセットを読み込まずに検索アセットレジストリのクエリ
実行時に複数のソース間で行を共有データレジストリ
Project Settings のプロジェクト全体で使う調整可能な値プロジェクト設定

データコンテナーの選択

必要なもの使用するものヘッダー
オブジェクトごとの設定、エディターで作成、エントリごとに 1 つのアセットUDataAssetEngine/DataAsset.h
同上。ID による読み込み/アンロードとクックルールにも対応UPrimaryDataAssetEngine/DataAsset.h
同じ形式のフラットな行、スプレッドシートで作成UDataTable + FTableRowBaseEngine/DataTable.h
複数のテーブルから行を統合(DLC、オーバーライド)UCompositeDataTableEngine/CompositeDataTable.h
行名をキーとする浮動小数点カーブUCurveTable、FCurveTableRowHandleEngine/CurveTable.h
実行時に複数のソースから解決する 1 つの行 IDUDataRegistrySubsystemDataRegistrySubsystem.h
Project Settings のプロジェクト全体で使う調整可能な値UDeveloperSettingsEngine/DeveloperSettings.h

UDataAsset は Blueprint サブクラスと継承に対応していますが、UDataTable の行は対応していません。UDataTable では、標準で行名による検索ができます。データアセットを検索可能にするには、Asset Manager のスキャンか Asset Registry のクエリが必要です。

データアセット

UDataAssetは、コンテンツブラウザーからインスタンス化できる通常のUObjectです。UPrimaryDataAssetはGetPrimaryAssetId()を追加し、UAssetManagerがIDでスキャン、ロード、アンロードできるようにします。

// MyWeaponDefinition.h
#pragma once

#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "MyWeaponDefinition.generated.h"
class UTexture2D; class USkeletalMesh;   // TSoftObjectPtr<T> needs T declared

UCLASS(BlueprintType)
class MYGAME_API UMyWeaponDefinition : public UPrimaryDataAsset
{
    GENERATED_BODY()

public:
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
    FText WeaponName;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
    float FireRate = 1.f;

    /** Written into the Asset Registry so it can be filtered without loading. */
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon", AssetRegistrySearchable)
    FName WeaponClassTag;

    /** Bundles group soft references so the Asset Manager can load a subset. */
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Art", meta = (AssetBundles = "UI"))
    TSoftObjectPtr<UTexture2D> Icon;

    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Art", meta = (AssetBundles = "Game"))
    TSoftObjectPtr<USkeletalMesh> WorldMesh;
};

GetPrimaryAssetId()のルール(Engine/DataAsset.h:36-53):

  • デフォルトでは、型は階層をさかのぼったときの最初のネイティブクラスの名前(または最上位のブループリントクラス)、名前はアセットのFNameが返されます。
  • ブループリントのサブクラスは、Data Assetインスタンスではなく、データのみのブループリントとして作成してください。そうすることで、親クラスの編集が反映されます。
  • 型や名前の方式を変更する必要がある場合に限りオーバーライドしてください。クラス本体内での宣言はvirtual FPrimaryAssetId GetPrimaryAssetId() const override;です。
  • UpdateAssetBundleData()は、クラスのmeta=(AssetBundles="Name")をスキャンし、PreSave中にAssetBundleData UPROPERTYを設定します。バンドル名は任意です。meta=(AssetBundles="Client,Server")とすると、1つのプロパティが2つのバンドルに追加されます。
  • 通常のUDataAssetにはプライマリアセットIDがなく、それを参照するものを通じてのみロードされます。

データテーブル

すべての行構造体はFTableRowBase(Engine/DataTable.h:33)を継承し、GENERATED_BODY()を使用します。

// MyItemTableRow.h
#pragma once

#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "MyItemTableRow.generated.h"
class UStaticMesh;

USTRUCT(BlueprintType)
struct FMyItemTableRow : public FTableRowBase
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    FText DisplayName;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    int32 MaxStack = 1;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    TSoftObjectPtr<UStaticMesh> PreviewMesh;

    /** Called after CSV/JSON import. Not editor-only. */
    virtual void OnPostDataImport(const UDataTable* InDataTable, const FName InRowName, TArray<FString>& OutCollectedImportProblems) override;

    /** Called for every row whenever the owning table is modified. Not editor-only. */
    virtual void OnDataTableChanged(const UDataTable* InDataTable, const FName InRowName) override;
};

FTableRowBase::IsDataValid(FDataValidationContext& Context) constは3つ目のフックであり、#if WITH_EDITORで囲まれています(Engine/DataTable.h:60-68)。オーバーライドも同じようにガードし、Misc/DataValidation.hをインクルードしてください。

検索
UPROPERTY(EditDefaultsOnly, Category = "Data")
TObjectPtr<UDataTable> ItemTable;

// FindRow<T>(FName, const TCHAR*|const FString&, bool bWarnIfRowMissing = true) -> T* or nullptr.
const FMyItemTableRow* Row = ItemTable->FindRow<FMyItemTableRow>(RowName, TEXT("LookupItem"));

TArray<FMyItemTableRow*> AllRows;
ItemTable->GetAllRows<FMyItemTableRow>(TEXT("GetAllItems"), AllRows);

TArray<FName> RowNames = ItemTable->GetRowNames();

ItemTable->ForeachRow<FMyItemTableRow>(TEXT("Foreach"),
    [](const FName& Key, const FMyItemTableRow& Value)
    {
        // Key is the row name, Value the typed row.
    });

// GetRowMap() is the raw TMap<FName, uint8*>; use it only for generic/reflection code.
const int32 NumRows = ItemTable->GetRowMap().Num();

FDataTableRowHandleは、デザイナーがエディターで選択できる、UPROPERTY向けの参照(テーブルと行名)です。

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config")
FDataTableRowHandle StartingItemHandle;   // IsNull() when nothing is picked

const FMyItemTableRow* Starting = StartingItemHandle.GetRow<FMyItemTableRow>(TEXT("StartingItem"));
実行時の変更とインポート
FMyItemTableRow NewRow;
NewRow.MaxStack = 5;
ItemTable->AddRow(FName(TEXT("RuntimeSword")), NewRow);   // In memory only, not saved to disk.
ItemTable->RemoveRow(FName(TEXT("ObsoleteItem")));
ItemTable->HandleDataTableChanged();                      // Fires the per-row OnDataTableChanged hooks.

// RowStruct must already be set. Available in all build configurations.
TArray<FString> Problems = ItemTable->CreateTableFromCSVString(CsvContent);
TArray<FString> JsonProblems = ItemTable->CreateTableFromJSONString(JsonContent);

GetTableAsCSV()、GetTableAsJSON()、GetTableAsString()は#if WITH_EDITOR内にあるため(Engine/DataTable.h:318-345)、クック済みビルドには存在しません。テーブルアセットのbStripFromClientBuildsを設定すると、NeedsLoadForClient()がfalseを返すため、サーバー専用のテーブルはクライアントに配布されません(Engine/DataTable.h:117,149)。

ブループリントからのアクセス

UDataTableFunctionLibrary(Kismet/DataTableFunctionLibrary.h)は、ブループリントからテーブルを利用できるようにします。利用できる関数は、GetDataTableRowFromName、DoesDataTableRowExist、GetDataTableRowNames、GetDataTableColumnNames、GetDataTableColumnAsString、GetDataTableRowStruct、EvaluateCurveTableRow、GetCurveTableRowNamesに加え、エディタースクリプト用のFillDataTableFromCSVString/FillDataTableFromCSVFileです。

カーブテーブルと複合テーブル

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Scaling")
FCurveTableRowHandle DamageCurve;

float ScaledDamage = DamageCurve.Eval(CharacterLevel, TEXT("ScaleDamage"));

// Or take the curve once for repeated sampling.
const FRealCurve* Curve = DamageCurve.GetCurve(TEXT("ScaleDamage"));

FCurveTableRowHandleには、GetRichCurve()、GetSimpleCurve()、IsNull()、Eval(float XValue, float* YValue, const FString& ContextString)もあり、検索が成功したかどうかを返します。

UCompositeDataTableはParentTables配列を1つの行マップに統合します。後のテーブルは、行名が重複する場合に前のテーブルを上書きします。基本ゲームとDLC、またはプラットフォームごとのオーバーライドに使用します。AppendParentTables()、RemoveParentTables()、GetParentTables()でスタックを管理します。AddRowとRemoveRowは何もしないようにオーバーライドされているため(Engine/CompositeDataTable.h:43-47、CompositeDataTable.cpp:191-204)、親テーブルを編集してください。

参照:ハード参照とソフト参照

形式所有者のロード時に対象をロード用途
TObjectPtr<UStaticMesh>はい常に必要なアセット、小さなアセット、またはすでに常駐しているアセット
TSubclassOf<AActor>はい(クラス)頻繁にスポーンするクラス
TSoftObjectPtr<UStaticMesh>いいえデータから参照されるアート、オーディオ、VFX
TSoftClassPtr<AActor>いいえデータで選択されるブループリントクラス
FSoftObjectPathいいえ汎用システムで使う型なしのパス
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Art")
TSoftObjectPtr<UStaticMesh> MeshSoft;

UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Spawning")
TSoftClassPtr<AActor> SpawnableSoft;   // LoadSynchronous() returns UClass*

const FSoftObjectPath MeshPath = MeshSoft.ToSoftObjectPath();

// State checks, no loading.
const bool bNoPathSet   = MeshSoft.IsNull();
const bool bInMemory    = MeshSoft.IsValid();   // path set AND target resolved in memory
const bool bLoadPending = MeshSoft.IsPending(); // path set, target not in memory yet
UStaticMesh* Resident   = MeshSoft.Get();       // nullptr unless already loaded

// Blocking resolution. Avoid on the game thread outside loading screens.
UStaticMesh* Mesh = MeshSoft.LoadSynchronous();
UObject* Loaded   = MeshPath.TryLoad();         // nullptr if missing, does not assert
UObject* Existing = MeshPath.ResolveObject();   // in-memory only, never loads

UPrimaryDataAsset内のハード参照は、定義のロード時に依存関係チェーン全体をメモリに読み込みます。これは、データ駆動型プロジェクトでメモリ使用量が際限なく増える最大の原因です。コンテンツにはソフト参照を、値や小さな構造体にはハード参照をデフォルトとして使用してください。

非同期ロード

FStreamableManager (Engine/StreamableManager.h) はアセットマネージャーが所有しています。UAssetManager::GetStreamableManager() から取得し、ゲームコードで独自に構築しないでください。

RequestAsyncLoad には2つの形式があります。従来の形式では、パス、デリゲート、TAsyncLoadPriority Priority、bool bManageActiveHandle、bool bStartStalled、FString DebugName の順に指定します。パラメーター形式では、単一の FStreamableAsyncLoadParams&& を指定します。

// AMyPickupActor members: the handle owns the load, so it must not be a local.
TSharedPtr<FStreamableHandle> LoadHandle;
UPROPERTY(EditDefaultsOnly, Category = "Art")
TSoftObjectPtr<UStaticMesh> MeshSoft;
UPROPERTY(VisibleAnywhere, Category = "Art")
TObjectPtr<UStaticMeshComponent> MeshComponent;

void AMyPickupActor::BeginLoadMesh()
{
    FStreamableManager& SM = UAssetManager::GetStreamableManager();

    LoadHandle = SM.RequestAsyncLoad(
        MeshSoft.ToSoftObjectPath(),
        FStreamableDelegate::CreateUObject(this, &AMyPickupActor::OnMeshLoaded),
        FStreamableManager::AsyncLoadHighPriority,
        /*bManageActiveHandle=*/false,
        /*bStartStalled=*/false,
        TEXT("Pickup mesh"));
}

void AMyPickupActor::OnMeshLoaded()
{
    if (UStaticMesh* Mesh = MeshSoft.Get())
    {
        MeshComponent->SetStaticMesh(Mesh);   // Component now holds a hard reference.
    }
    LoadHandle.Reset();
}

キャンセル/更新デリゲートやJITによる段階的なリクエスト送信が必要な場合は、パラメーター形式を使用します。

FStreamableAsyncLoadParams Params;
Params.TargetsToStream = { IconSoft.ToSoftObjectPath(), MeshSoft.ToSoftObjectPath() };
Params.Priority = FStreamableManager::AsyncLoadHighPriority;
Params.bUseJustInTimeAsyncLoader = true;
Params.OnComplete = FStreamableDelegateWithHandle::CreateWeakLambda(this,
    [this](TSharedPtr<FStreamableHandle> Handle)
    {
        // Both targets resolved.
    });

LoadHandle = SM.RequestAsyncLoad(MoveTemp(Params), TEXT("Pickup bundle"));

RequestSyncLoad(TargetsToStream, bManageActiveHandle = false, DebugName = FString()) は完了するまでブロックします。ロード画面や一度限りの初期化にのみ使用してください。

FStreamableHandle のメンバー意味
IsActive()リクエストが存在し、解放もキャンセルもされていません
HasLoadCompleted()すべての対象のロードが完了しています(デリゲートはまだ実行されていない場合があります)
IsLoadingInProgress()ストリーミング中です
WasCanceled() / HasError()自分でキャンセルした/1つ以上の対象で失敗しました
GetLoadProgress()0.0~1.0
GetLoadedAsset() / GetLoadedAsset<T>()最初の対象です。すべての対象を取得するには GetLoadedAssets(TArray<T*>&) を使用します
WaitUntilComplete(float Timeout = 0.f, bool bStartStalledHandles = true)呼び出し元をブロックし、EAsyncPackageState::Type を返します
BindCompleteDelegate / BindCancelDelegate / BindUpdateDelegateリクエスト作成後にコールバックを設定します
CancelHandle()ロードを停止します。完了デリゲートは実行されません
ReleaseHandle()ストリーミング参照を解放し、アセットを回収可能にします

ハンドルが参照そのものです。 RequestAsyncLoad でロードされたアセットは、そのリクエストへの TSharedPtr<FStreamableHandle> が存続している間(または bManageActiveHandle が true の場合)に限り生存します。完了前にすべてのポインターを破棄しても、キャンセルにはなりません。マネージャーは完了デリゲートが実行されるまでハンドルを保持し、その後解放します(Engine/StreamableManager.h:316-320)。そのため、ほかに強参照がなければ、次回のGCでアセットを回収できます。

デリゲートファクトリー:FStreamableDelegate::CreateUObject(this, &UMyLoader::Fn)(オブジェクトをチェックするため安全)、CreateWeakLambda(this, Lambda)(安全。所有者が破棄されると破棄します)、CreateLambda(Lambda)(キャプチャした this を使う場合は安全ではありません)。

UE_ENABLE_STREAMABLE_JIT_ASYNC_LOADING (Engine/StreamableManager.h:20) はデフォルトで 0 であり、JIT非同期ローダーをコンパイル時に有効化します。s.StreamableEnableJITAsyncLoading は、bUseJustInTimeAsyncLoader でオプトインしたリクエストに対して有効にします。s.StreamableEnableJITAsyncLoadingGlobally は、すべてのリクエストに対して強制的に有効にします。JITはリクエストを一度にすべてキューに入れるのではなく、非同期ローダーに段階的に送信するため、高負荷時でも優先順位付けとキャンセルへの応答性を維持できます。FStreamableHandle::IsUsingJustInTimeAsyncLoader() で、最終的に適用された状態を確認できます。

バッチ処理、結合ハンドル、進行状況、キャンセルなど、さらに詳しいパターンについては、アセットロードのパターンを参照してください。

アセットマネージャー

UAssetManager は、[/Script/Engine.Engine] AssetManagerClassName を通じて登録されるグローバルシングルトンです。サブクラス化して StartInitialLoading() と PostInitialAssetScan() をオーバーライドします。

UAssetManager& AM = UAssetManager::Get();               // Engine/AssetManager.h:97

TArray<FPrimaryAssetId> WeaponIds;
AM.GetPrimaryAssetIdList(FPrimaryAssetType(TEXT("MyWeaponDefinition")), WeaponIds);

const FPrimaryAssetId WeaponId(FPrimaryAssetType(TEXT("MyWeaponDefinition")), FName(TEXT("DA_Sword")));
TSharedPtr<FStreamableHandle> Handle = AM.LoadPrimaryAsset(
    WeaponId,
    TArray<FName>{ TEXT("Game") },
    FStreamableDelegate::CreateUObject(this, &UMyItemSubsystem::OnWeaponLoaded));

UMyWeaponDefinition* Def = AM.GetPrimaryAssetObject<UMyWeaponDefinition>(WeaponId);
AM.ChangeBundleStateForPrimaryAssets(
    { WeaponId },
    TArray<FName>{ TEXT("Game") },   // AddBundles
    TArray<FName>{ TEXT("UI") });    // RemoveBundles
const int32 NumUnloaded = AM.UnloadPrimaryAsset(WeaponId);

シグネチャ(Engine/AssetManager.h:333,340):

virtual TSharedPtr<FStreamableHandle> LoadPrimaryAsset(
    const FPrimaryAssetId& AssetToLoad,
    const TArray<FName>& LoadBundles = TArray<FName>(),
    FStreamableDelegate DelegateToCall = FStreamableDelegate(),
    TAsyncLoadPriority Priority = FStreamableManager::DefaultAsyncLoadPriority,
    UE::FSourceLocation Location = UE::FSourceLocation::Current());

virtual TSharedPtr<FStreamableHandle> LoadPrimaryAsset(
    const FPrimaryAssetId& AssetToLoad,
    const TArray<FName>& LoadBundles,
    FAssetManagerLoadParams&& LoadParams,
    UE::FSourceLocation Location = UE::FSourceLocation::Current());

LoadPrimaryAssets(複数形)、LoadPrimaryAssetsWithType、ChangeBundleStateForPrimaryAssets、ChangeBundleStateForMatchingPrimaryAssets は、いずれも同じ2種類の形式があります。Location はコンパイラーによって入力されるため、渡さないでください。新しいコードでは FAssetManagerLoadParams オーバーロードを推奨します。OnComplete と OnCancel(どちらも FStreamableDelegateWithHandle)、OnUpdate、Priority を指定できます。

生のストリーミング可能なリクエストとは異なり、プライマリアセットはアンロードするまでロードされたままです。返されたハンドルを保持する必要はなく、ポーリングまたは完了待ちにのみ使用します。

ScanPathsForPrimaryAssets(FPrimaryAssetType, const TArray<FString>& Paths, UClass* BaseClass, bool bHasBlueprintClasses, bool bIsEditorOnly = false, bool bForceSynchronousScan = true) は、設定によるスキャンだけでは不十分な場合に、コードからタイプを登録します。AddDynamicAsset(const FPrimaryAssetId&, const FSoftObjectPath&, const FAssetBundleData&) は、実行時に生成されたプライマリアセットを登録します。

クックルール

; DefaultGame.ini
[/Script/Engine.AssetManagerSettings]
+PrimaryAssetTypesToScan=(PrimaryAssetType="MyWeaponDefinition",AssetBaseClass="/Script/MyGame.MyWeaponDefinition",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/Data/Weapons")),Rules=(Priority=1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook))

FPrimaryAssetTypeInfo のフィールド(Engine/AssetManagerTypes.h:131):PrimaryAssetType、AssetBaseClass、bHasBlueprintClasses、bIsEditorOnly、Directories、SpecificAssets、Rules。FPrimaryAssetRules(Engine/AssetManagerTypes.h:66):Priority、ChunkId、bApplyRecursively、CookRule。

EPrimaryAssetCookRule(Engine/AssetManagerTypes.h:28):

値意味
Unknown参照されている場合に限り、開発ビルドと製品ビルドでクックされます
NeverCookクックされません。これへの依存はエラーになります
ProductionNeverCook参照されている場合は開発ビルドでクックされますが、製品ビルドではクックされません
DevelopmentAlwaysProductionNeverCook開発ビルドでは常にクックされますが、製品ビルドではクックされません
DevelopmentAlwaysProductionUnknownCook開発ビルドでは常にクックされ、製品ビルドでは参照されている場合に限りクックされます
AlwaysCookどちらのビルドでも常にクックされます

UAssetManagerSettings(config = Game、defaultconfig)には、DirectoriesToExclude、PrimaryAssetRules、CustomPrimaryAssetRules、bOnlyCookProductionAssets もあります。リリース用ブランチでは最後の項目を有効にし、ProductionNeverCook アセットがビルドに混入する代わりにエラーになるようにします。

スキャン済みのプライマリアセットからもハード参照からも到達できないアセットはクックされません。ソフト参照だけではアセットはクック対象になりません。プライマリアセットタイプまたは UPrimaryAssetLabel を付与してください。

アセットレジストリのクエリ

IAssetRegistry は、アセットをロードせずにアセットのメタデータを読み取ります。

#include "AssetRegistry/ARFilter.h"
#include "AssetRegistry/AssetData.h"
#include "AssetRegistry/IAssetRegistry.h"

IAssetRegistry& AR = IAssetRegistry::GetChecked();   // AssetRegistry/IAssetRegistry.h:272

FARFilter Filter;
Filter.PackagePaths.Add(FName(TEXT("/Game/Data/Weapons")));
Filter.bRecursivePaths = true;
Filter.ClassPaths.Add(FTopLevelAssetPath(TEXT("/Script/MyGame"), TEXT("MyWeaponDefinition")));
Filter.bRecursiveClasses = true;

TArray<FAssetData> Found;
AR.GetAssets(Filter, Found);

// Direct call; the class argument is FTopLevelAssetPath, never FName.
AR.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/MyGame"), TEXT("MyWeaponDefinition")), Found, /*bSearchSubClasses=*/true);

for (const FAssetData& Data : Found)
{
    const FTopLevelAssetPath ClassPath = Data.AssetClassPath;   // Data.AssetName for the short name.

    FString TagValue;
    Data.GetTagValue(FName(TEXT("WeaponClassTag")), TagValue);  // Registry read, still no load.

    UObject* Asset = Data.GetAsset();                           // This one does load.
}

IAssetRegistry::Get() は、モジュールが起動する前には null を返す可能性があります。GetChecked() は代わりにアサートし、FAssetRegistryModule::GetRegistry() はモジュールレベルで同等の機能を提供します。UPROPERTY に AssetRegistrySearchable を指定すると、そのプロパティがレジストリに書き込まれるため、アセットをロードせずに FARFilter::TagsAndValues と GetAssetsByTagValues でフィルタリングできます。アセットがまだ検出されていない可能性がある場合は、ScanPathsSynchronous() を使用してください。

データレジストリ

DataRegistry(5.8 ではベータ版。プラグインはデフォルトで無効、モジュールは DataRegistry)は、1 つの FDataRegistryId をデータテーブル、カーブテーブル、またはカスタムソースからなるチェーンと照合します。これにより、ゲームプレイコードはどのテーブルや DLC が提供元かを把握せずに、ID で項目を取得できます。

#include "DataRegistryId.h"
#include "DataRegistrySubsystem.h"

UDataRegistrySubsystem* Registry = UDataRegistrySubsystem::Get();
const FDataRegistryId ItemId(FName(TEXT("ItemRegistry")), FName(TEXT("Sword")));

// Cached read: non-null only if the source is already resident.
const FMyItemTableRow* Row = Registry->GetCachedItem<FMyItemTableRow>(ItemId);

// Otherwise request it, then re-query the cache in the callback.
Registry->AcquireItem(ItemId, FDataRegistryItemAcquiredCallback::CreateWeakLambda(this,
    [ItemId](const FDataRegistryAcquireResult& Result)
    {
        const FMyItemTableRow* Acquired =
            UDataRegistrySubsystem::Get()->GetCachedItem<FMyItemTableRow>(ItemId);
    }));

UDataRegistrySource_DataTable は FDataRegistrySource_DataTableRules(bPrecacheTable、CachedTableKeepSeconds)とともに TSoftObjectPtr<UDataTable> SourceTable を指定してレジストリを参照するテーブルを設定します。UDataRegistrySource_CurveTable もカーブに対して同様の設定を行います。レジストリアセットは UDataRegistrySettings を通じて設定します。

プロジェクト設定

UDeveloperSettings(モジュール DeveloperSettings)はクラスをプロジェクト設定に自動登録し、クラス名に基づく ini セクションから設定を読み込みます。

クラスを UCLASS(config = Game, defaultconfig, meta = (DisplayName = "My Game")) として宣言し、UDeveloperSettings を継承します。各フィールドには UPROPERTY(config, EditAnywhere, Category = "Economy") を指定し、GetDefault<UMyGameSettings>() で読み取ります。config = Game と defaultconfig を指定すると、DefaultGame.ini の [/Script/MyGame.MyGameSettings] に書き込まれます。ページの配置を変更するには、GetContainerName()、GetCategoryName()、または GetSectionName() をオーバーライドします。少数のグローバルな調整可能値にはこの方法を使い、デザイナーが項目ごとに調整するデータにはデータアセットを使ってください。インクルードと Build.cs の依存関係を含む完全なクラスは、データ駆動型設計パターンにあります。

非推奨 — 使用しないでください

使用しない5.8 で使用出典
TAssetPtr<T>, TAssetSubclassOf<T>TSoftObjectPtr<T>, TSoftClassPtr<T>5.8 のヘッダーには存在しません。UObject/SoftObjectPtr.h:173,795
FStringAssetReferenceFSoftObjectPath5.8 のヘッダーには存在しません。UObject/SoftObjectPath.h
UAssetManager::IsValid(), GetIfValid()IsInitialized(), GetIfInitialized()Engine/AssetManager.h:91,99 で UE_DEPRECATED(5.3)
OnAssetStateChangeCompleted(...) のオーバーライドNotifyOnAssetStateChangeCompletedEngine/AssetManager.h:1035 で UE_DEPRECATED(5.6)
LoadAssetListInternal(...)FAssetManagerLoadParams を受け取る LoadAssetList(...)Engine/AssetManager.h:1072 で UE_DEPRECATED(5.6)
ShouldSetManager(Manager, Source, Target, ...)ShouldSetManager(UE::AssetRegistry::FShouldSetManagerContext&)Engine/AssetManager.h:1082 で UE_DEPRECATED(5.6)
UpdateManagementDatabase(bool)UpdateManagementDatabase(EUpdateManagementDatabaseFlags)Engine/AssetManager.h:924 で UE_DEPRECATED(5.6)
BuildChunkMap(PackagesToUpdateChunksFor)3 引数の BuildChunkMapEngine/AssetManager.h:1129 で UE_DEPRECATED(5.6)
FAssetData::AssetClass(短縮名)FAssetData::AssetClassPath(FTopLevelAssetPath)AssetRegistry/AssetData.h:198 で UE_DEPRECATED(5.1)
GetAssetsByClass(FName ClassName, ...)GetAssetsByClass(FTopLevelAssetPath, ...)AssetRegistry/IAssetRegistry.h:335
配列を返す UCurveTable::GetCurves()GetCurves(TAdderReserverRef<FRichCurveEditInfoConst>)Engine/CurveTable.h:106 で UE_DEPRECATED(5.6)
UDataTable::RowStructName実行時には GetRowStruct()。RowStructPathName は WITH_EDITORONLY_DATAEngine/DataTable.h:168 の RowStructName_DEPRECATED。GetRowStruct() は :110
行構造体の GENERATED_USTRUCT_BODY()GENERATED_BODY()どちらもコンパイルできますが、現在の標準スタイルは後者のみです
Build.cs の依存関係リストにある "AssetManager""Engine"そのようなモジュールはありません。Engine/Classes/Engine/AssetManager.h

よくある間違い

ストリーミング可能なハンドルを破棄してしまう: 読み込まれたアセットはソフトポインターではなく、ハンドルによって参照されます。ハード参照(コンポーネント、TObjectPtr、配列)がアセットを所有するまで、TSharedPtr<FStreamableHandle> をメンバーとして保持し、その後リセットしてください。

データアセットからコンテンツをハード参照する: UPrimaryDataAsset 内の TObjectPtr<UNiagaraSystem> は、定義と一緒にエフェクトを読み込みます。TSoftObjectPtr とアセットバンドルを使用してください。

Tick やゲームプレイ上重要な処理で LoadSynchronous() を呼び出す: アセットがすでにメモリ上にない場合、ゲームスレッドが停止します。非同期読み込みを一度開始し、コールバック内で処理してください。

GetAssetsByClass に FName を渡す: 5.8 では FTopLevelAssetPath(TEXT("/Script/Module"), TEXT("ClassName")) が必要です。短いクラス名ではコンパイルできません。

PrimaryAssetTypesToScan の設定を忘れる: タイプが登録されていないと、GetPrimaryAssetIdList は何も返さず、LoadPrimaryAsset は何もせずに終了します。DefaultGame.ini でタイプを登録するか、ScanPathsForPrimaryAssets を呼び出してください。

単純な CreateLambda で this をキャプチャする: オブジェクトが破棄された後にコールバックが呼び出される可能性があります。CreateUObject または CreateWeakLambda(this, Lambda) を使用してください。

実行時に GetTableAsCSV() を呼び出す: これは WITH_EDITOR のみで利用でき、クック済みビルドではリンクされません。代わりに行を自分でシリアライズしてください。同様に、行構造体のプロパティ名を変更または削除すると、次回のインポート時に既存の行からその列が失われます。構造体を変更する前にテーブルを CSV にエクスポートし、その後再インポートしてください。

関連スキル

  • ue-cpp-foundations — UPROPERTY/USTRUCT 指定子、TObjectPtr、UObject のライフサイクル、サブシステムの一覧
  • ue-async-threading — ストリーミング読み込み以外の一般的な非同期処理のイディオム(UE::Tasks、Async、FTSTicker)
  • ue-serialization-savegames — セッション間でのソフトオブジェクトパスとプライマリアセット ID の永続化
  • ue-game-features — プラグイン内のデータアセットの配布とゲーム機能のアセットスキャン
  • ue-gameplay-abilities — これらのデータアセットを使用するアビリティとエフェクトの定義
  • ue-world-level-streaming — レベルストリーミング、World Partition、Data Layers
  • ue-module-build-system — Build.cs への AssetRegistry、DeveloperSettings、プラグインモジュールの追加
  • ue-audio-system — UAudioComponent、MetaSounds、サブミックス、減衰、同時実行
  • ue-blueprint-cpp-interop — C++ の Blueprint への公開:UFUNCTION/UPROPERTY のメタキー、潜在アクション、非同期ノード
  • ue-editor-tools — 詳細パネルのカスタマイズ、エディターユーティリティウィジェット、UToolMenus、エディターサブシステム
  • ue-gameplay-tags-messaging — ネイティブおよび ini のゲームプレイタグ、コンテナー、クエリ、非同期メッセージシステム
  • ue-materials-rendering — マテリアルインスタンス、パラメーターコレクション、レンダーターゲット、ポストプロセス
  • ue-procedural-generation — PCG グラフ、プロシージャルメッシュとダイナミックメッシュ、インスタンシング、スプライン
  • ue-ui-umg-slate — UMG ウィジェット、Slate、Common UI、MVVM

コメント