kevinpbuckley/unreal-engine-skills

ue-data-driven-design

Drive Unreal gameplay from externally-editable data instead of hardcoded values — DataTables (UDataTable, FTableRowBase, CSV/JSON import, UCompositeDataTable), DataAssets (UDataAsset, UPrimaryDataAsset with AssetManager), Curves (UCurveFloat, UCurveTable, F…

Ver código fuente

Cómo usar

  1. Copia el comando y revisa el paquete antes de instalarlo en tu entorno de agente.
  2. Consulta las herramientas, credenciales y entornos necesarios en el documento original.
  3. Describe las entradas y el resultado deseado; contrasta la salida con las fuentes.
npx skills add https://github.com/kevinpbuckley/unreal-engine-skills --skill ue-data-driven-design

Antes de empezar

  • La instalación no incluye suscripción al modelo, cuota API ni permisos sobre tus archivos.
  • Las estrellas e instalaciones reflejan actividad, no una prueba independiente de calidad o seguridad.
Documento original del Skill

Contenido del repositorio de origen con títulos, ejemplos, código, tablas, enlaces e imágenes preservados.

Data-driven design

Hardcoding gameplay values (item stats, enemy configs, balance numbers, curves) makes iteration slow and risky. Move them into assets and config objects that designers can edit without recompiling. The choice of container drives every downstream workflow.

When to use this skill

  • Defining sets of similar records (items, enemies, weapons, abilities, loot).
  • One-off structured config objects (boss setup, game-mode tuning, single-character stats).
  • Values that vary over an input (damage falloff, XP per level, camera ease curves).
  • Replacing magic numbers with .ini-backed project settings editable in Project Settings.
  • Layering or overriding rows across game modes, DLC, or platforms (composite tables).

Pick the right container

NeedUse
Many rows of the same schema, bulk spreadsheet workflow`UDataTable`
Layered/overriding rows across DLC or variants`UCompositeDataTable`
A single rich config object, possibly subclassed`UDataAsset` / `UPrimaryDataAsset`
A value that depends on another (falloff, curves)`UCurveFloat` / `UCurveTable`
An inline editable curve inside a struct/component`FRuntimeFloatCurve`
Global programmer-near settings in .ini`UCLASS(Config=X)` + `UPROPERTY(config)`
Project Settings panel entry with change notifications`UDeveloperSettings`

DataTables — tabular records

Define a row struct inheriting FTableRowBase, then create a DataTable asset in the Content Browser (or import CSV/JSON). The table stores rows as a TMap<FName, uint8*> internally, accessed through typed template helpers.

cpp
// ItemRow.h — one USTRUCT per table schema
USTRUCT(BlueprintType)
struct FItemRow : public FTableRowBase
{
    GENERATED_BODY()
    UPROPERTY(EditAnywhere, BlueprintReadWrite) FText  DisplayName;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) int32  Price    = 0;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) float  Weight   = 1.f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) TSoftObjectPtr<UTexture2D> Icon;
};
cpp
// Runtime lookup — context string appears in log if the row is missing
if (const FItemRow* Row = ItemTable->FindRow<FItemRow>(TEXT("Sword_Iron"), TEXT("ItemQuery")))
{
    float w = Row->Weight;
}

// Iterate every row
ItemTable->ForeachRow<FItemRow>(TEXT("PopulateShop"),
    [](const FName& Key, const FItemRow& Row) { /* ... */ });

// Typed bulk access
TArray<FItemRow*> All;
ItemTable->GetAllRows<FItemRow>(TEXT("All"), All);

Key macro rule: the struct needs USTRUCT(BlueprintType) so Blueprint graphs can read rows; FTableRowBase is the mandatory base (DataTable.h:33).

`FDataTableRowHandle` (DataTable.h:424) — a two-field struct (table + row name) you expose as a UPROPERTY so designers pick the exact row in the Details panel, eliminating string typos.

cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite) FDataTableRowHandle RewardRow;
// At runtime:
if (const FItemRow* R = RewardRow.GetRow<FItemRow>(TEXT("Reward"))) { ... }

`UCompositeDataTable` (CompositeDataTable.h:13) — a UDataTable subclass that stacks parent tables; higher-index parents win on duplicate row names. Use for DLC or per-platform row overrides without duplicating the base table. See references/datatables-and-composite.md.

DataAssets — structured config objects

A UDataAsset is a UObject subclass you create as an asset. Inherit it for rich single-record configs; override properties in Blueprint Data Only subclasses for per-instance variation.

cpp
// EnemyConfig.h
UCLASS(BlueprintType)
class MYGAME_API UEnemyConfig : public UPrimaryDataAsset
{
    GENERATED_BODY()
public:
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Stats")
    float MaxHealth = 100.f;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Spawning")
    TSoftClassPtr<APawn> PawnClass;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Tags")
    FGameplayTagContainer Traits;
};
  • UDataAsset (DataAsset.h:17) — base; creates assets in the Content Browser, hard-loaded

when the outer object is loaded.

  • UPrimaryDataAsset (DataAsset.h:47) — adds GetPrimaryAssetId() for UAssetManager

discovery, async loading, and bundle-based streaming. Use when you need lifecycle control or have many instances (hundreds of items). See ue-asset-management.

Reference instances as TObjectPtr<UEnemyConfig> (hard, loads immediately) or TSoftObjectPtr<UEnemyConfig> (lazy, loaded on demand). DataAssets beat DataTables when each record needs inheritance, rich nested types, or Blueprint subclassing.

See references/data-assets-and-validation.md.

Curves

Use curves when a value depends on a continuous input (time, distance, level).

TypeStorageEvaluation
UCurveFloatstandalone assetCurve->GetFloatValue(X)
UCurveTablemany named curves in one assetTable->FindRichCurve(Name, Context)
FRuntimeFloatCurveembedded in a struct/componentCurve.GetRichCurve()->Eval(X)
cpp
// Standalone curve asset property
UPROPERTY(EditAnywhere, Category="Balance") TObjectPtr<UCurveFloat> DamageFalloff;

float GetDamage(float Distance) const
{
    return BaseDamage * (DamageFalloff ? DamageFalloff->GetFloatValue(Distance) : 1.f);
}
cpp
// Inline curve — editable in the Details panel without a separate asset
UPROPERTY(EditAnywhere, Category="Motion") FRuntimeFloatCurve SpeedOverTime;

float GetSpeed(float T) const
{
    const FRichCurve* C = SpeedOverTime.GetRichCurveConst();
    return C ? C->Eval(T) : 0.f;
}

UCurveFloat (CurveFloat.h:30) wraps a FRichCurve and is the standard designer-facing single-axis float curve. FRuntimeFloatCurve (CurveFloat.h:12) lets you bake the curve inline or point at an external UCurveFloat asset.

See references/curves-and-runtime-data.md.

Config-driven properties (.ini files)

For global, programmer-near defaults that ship with the project, mark the class and properties:

cpp
// Reads/writes Config/DefaultGame.ini under [/Script/MyGame.UGameBalanceSettings]
UCLASS(Config=Game, DefaultConfig)
class MYGAME_API UGameBalanceSettings : public UObject
{
    GENERATED_BODY()
public:
    UPROPERTY(Config, EditAnywhere, Category="Balance")
    float GlobalDamageScale = 1.f;

    UPROPERTY(Config, EditAnywhere, Category="Economy")
    int32 StartingGold = 500;
};

// Read anywhere:
const UGameBalanceSettings* S = GetDefault<UGameBalanceSettings>();
float Scale = S->GlobalDamageScale;

The .ini section name is [/Script/ModuleName.ClassName] (without the U prefix). DefaultConfig writes user edits back to Default<Category>.ini rather than a per-user file. Do not use this pattern for content-scale data (hundreds of records); use DataTables/DataAssets.

DeveloperSettings — Project Settings panel entries

UDeveloperSettings (DeveloperSettings.h:23, module DeveloperSettings) auto-discovers the class and adds it to Project Settings. Ideal for cross-system tuning knobs and references to key data assets that the rest of the codebase needs to find.

cpp
UCLASS(Config=Game, DefaultConfig, meta=(DisplayName="My Game Settings"))
class MYGAME_API UMyGameSettings : public UDeveloperSettings
{
    GENERATED_BODY()
public:
    UMyGameSettings() { CategoryName = TEXT("Game"); SectionName = TEXT("MyGameSettings"); }

    UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="Tables")
    TSoftObjectPtr<UDataTable> ItemTable;

    UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="Tuning")
    float DifficultyMultiplier = 1.f;

    // Convenience accessor
    static const UMyGameSettings* Get() { return GetDefault<UMyGameSettings>(); }
};
cpp
// Consuming code — no FindObject, no hard path
const UDataTable* Table = UMyGameSettings::Get()->ItemTable.LoadSynchronous();

Add DeveloperSettings to your module's PublicDependencyModuleNames in Build.cs.

See references/config-and-developer-settings.md.

Validation

Override IsDataValid on DataAssets and in row structs to surface content errors before runtime.

cpp
// In UEnemyConfig (editor-only)
#if WITH_EDITOR
virtual EDataValidationResult IsDataValid(FDataValidationContext& Context) const override
{
    EDataValidationResult Result = Super::IsDataValid(Context);
    if (MaxHealth <= 0.f)
        Context.AddError(FText::FromString(TEXT("MaxHealth must be > 0")));
    if (PawnClass.IsNull())
        Context.AddError(FText::FromString(TEXT("PawnClass is not set")));
    return Context.GetNumErrors() > 0 ? EDataValidationResult::Invalid : Result;
}
#endif

Run validation from the Content Browser (Asset Actions → Validate Assets) or via UnrealEditor-Cmd.exe MyProject.uproject -run=DataValidation for CI. The Data Validation plugin calls IsDataValid on UDataTable itself (engine implementation) and on UObject-derived assets that override it.

Gotchas

  • Wrong container shape — large flat datasets in individual DataAssets, or deeply nested

configs forced into DataTable rows — match the shape to the tool.

  • Hard refs to heavy assets in rows/assets — every row's hard ref loads at table load time;

use TSoftObjectPtr for textures, meshes, sounds, and class refs.

  • Row name typos in FindRow return null silently (with a log warning); prefer

FDataTableRowHandle pickers so designers pick from a validated list.

  • Forgetting `USTRUCT(BlueprintType)` on a row struct — Blueprint nodes that read rows will

fail to expose the type.

  • Editing CSV after adding struct fields — the column order and header names must match the

struct; add new fields at the end and re-import.

  • Composite table loop — UCompositeDataTable detects and rejects circular parent

references at load time, but keep the parent chain shallow.

  • `UDeveloperSettings` not showing — the module must be listed in PublicDependencyModuleNames;

also check that CategoryName maps to a known Project Settings category ("Game", "Engine", "Editor").

  • `GetDefault<T>()` vs `GetMutableDefault<T>()` — GetDefault is read-only and safe

anywhere; GetMutableDefault is for editor tooling or startup init only, never gameplay.

  • Config UPROPERTY for content data — .ini values are not asset-browser-visible and give

designers a worse authoring experience; use DataTables or DataAssets for game content.

Version notes

  • UCompositeDataTable has been stable since UE4. The AppendParentTables/RemoveParentTable

runtime API (CompositeDataTable.h:59–62) allows dynamic parent modification, but the comment in the header warns this can cause hitches during gameplay.

  • UDeveloperSettings is in its own module (DeveloperSettings) since UE5; in UE4 it was part

of Engine. Update Build.cs accordingly.

  • FRuntimeFloatCurve::GetRichCurveConst() is the const accessor added in UE5 to avoid the

const-correctness issues of the earlier mutable-only path.

  • FTableRowBase::IsDataValid signature matches UObject::IsDataValid(FDataValidationContext&)

introduced in UE5.1; do not use the older TArray<FText>& variant.

References & source material

Engine source (UE 5.8, under Engine/Source/Runtime/):

  • Engine/Classes/Engine/DataTable.h — FTableRowBase:33, UDataTable:76,

FindRow<T>:219, GetAllRows<T>:199, ForeachRow<T>:232, FDataTableRowHandle:424, FDataTableCategoryHandle:497.

  • Engine/Classes/Engine/CompositeDataTable.h — UCompositeDataTable:13,

ParentTables:83, AppendParentTables:59.

  • Engine/Classes/Engine/DataAsset.h — UDataAsset:17, UPrimaryDataAsset:47,

GetPrimaryAssetId():53.

  • Engine/Classes/Engine/CurveTable.h — UCurveTable:40, FindCurve:131,

FindRichCurve:150, FCurveTableRowHandle:262.

  • Engine/Classes/Curves/CurveFloat.h — FRuntimeFloatCurve:12,

UCurveFloat:30, GetFloatValue:44.

  • DeveloperSettings/Public/Engine/DeveloperSettings.h — UDeveloperSettings:23,

GetContainerName:31, GetCategoryName:33, GetSectionName:35.

Official docs (UE 5.8):

  • Data Assets — <https://dev.epicgames.com/documentation/unreal-engine/data-assets-in-unreal-engine>
  • Configuration Files — <https://dev.epicgames.com/documentation/unreal-engine/configuration-files-in-unreal-engine>
  • Data Validation — <https://dev.epicgames.com/documentation/unreal-engine/data-validation-in-unreal-engine>

Deep-dive references in this skill:

internals, CSV/JSON import, row callbacks, CompositeDataTable layering.

DataAsset vs PrimaryDataAsset, AssetManager integration, validation patterns.

UCurveFloat, UCurveTable, FRuntimeFloatCurve, FCurveTableRowHandle.

config UPROPERTY mechanics, DeveloperSettings setup, GetDefault, SaveConfig.

Related skills: ue-asset-management, ue-gameplay-tags, ue-project-structure, ue-cpp-fundamentals.

Relacionados por tarea

del mismo repositorio

Más Skills

Todos los Skills
kevinpbuckley
Comunidad

ue-character-and-movement

Implement player/AI characters in Unreal C++ with ACharacter and UCharacterMovementComponent — capsule/mesh setup, movement modes (walking/falling/flying/swimming/custom), rotation behaviors, jumping, crouching, root motion sources, client-predicted networked movement, and the experimental Mover plugin successor. Use when creating or configuring a Character class, setting movement speeds/gravity/air-control, overriding a custom movement mode (PhysCustom), adding root motion, or debugging network

instalaciones
1
GitHub Stars
60
Actualizado
1 oct
kevinpbuckley
Comunidad

ue-control-rig-and-ik

Procedural animation and inverse kinematics in Unreal Engine — Control Rig (RigVM-based graph that manipulates a bone/control hierarchy), IK Rig (solver definitions with Full-Body IK, Limb IK, Set Transform), the IK Retargeter (transfers animation between skeletons of different proportions), and lightweight AnimGraph IK nodes (Two Bone IK, FABRIK, CCDIK). Use when implementing foot placement on terrain, hand/weapon IK, look-at, procedural pose fixups, runtime retargeting, or sharing an animation

instalaciones
1
GitHub Stars
60
Actualizado
1 oct
kevinpbuckley
Comunidad

ue-core-types-and-containers

Use Unreal's core C++ types instead of the standard library — containers (TArray, TMap, TSet, TQueue, TArrayView), string types (FString, FName, FText, TStringBuilder) with conversion patterns and localization rules, math types (FVector, FRotator, FQuat, FTransform) with Large World Coordinates (LWC/double precision), and utility types (TOptional, TVariant, TTuple). Use when writing any UE C++ that stores collections, manipulates strings, does 3D math, or when choosing between FString/FName/ FTe

instalaciones
1
GitHub Stars
60
Actualizado
1 oct
kevinpbuckley
Comunidad

ue-delegates-and-events

Wire up callbacks and events in Unreal C++ using delegates — single-cast (DECLAREDELEGATE, DECLAREDELEGATERetVal, payload variables), multicast (DECLAREMULTICASTDELEGATE, DECLARETSMULTICASTDELEGATE), and dynamic (DECLAREDYNAMICMULTICASTDELEGATE, BlueprintAssignable, AddDynamic, RemoveDynamic). Covers all binding forms (BindUObject, AddUObject, BindLambda, AddWeakLambda, BindRaw, AddSP), execution (Execute, ExecuteIfBound, Broadcast), FDelegateHandle lifetime management, safe unbinding, and DECLA

instalaciones
1
GitHub Stars
60
Actualizado
1 oct