Unreal EngineMiddleTechnical

Что такое макросы UPROPERTY и UFUNCTION и какие параметры они поддерживают?

UPROPERTY регистрирует поле для GC, редактора, Blueprint и сериализации; UFUNCTION регистрирует метод для Blueprint, RPC и рефлексии. Оба поддерживают десятки параметров-спецификаторов, управляющих видимостью и поведением.

Макрос UPROPERTY

UPROPERTY сообщает системе рефлексии UE о поле класса. Без него GC не видит указатель на UObject, поле не появляется в редакторе и не сериализуется.

Спецификаторы UPROPERTY

  • EditAnywhere — редактируется в экземплярах и Blueprint-дефолтах.
  • EditDefaultsOnly — только в CDO (Class Default Object), не в экземплярах.
  • EditInstanceOnly — только в размещённых экземплярах.
  • VisibleAnywhere / VisibleDefaultsOnly — показать без редактирования.
  • BlueprintReadWrite / BlueprintReadOnly — доступность в Blueprint-графах.
  • Replicated — реплицировать по сети клиентам.
  • ReplicatedUsing=OnRep_FieldName — вызвать функцию при получении репликации.
  • Transient — не сериализовать (не сохранять в .uasset / сейв-файл).
  • SaveGame — включить в сейв через USaveGame.
  • Config — читать значение из .ini файла.
  • Category="Name" — группировка в деталях редактора.
UCLASS()
class AMyCharacter : public ACharacter
{
    GENERATED_BODY()
public:
    // Редактируется везде, доступно в BP, реплицируется
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category="Stats")
    float Health = 100.f;

    // Только в дефолтах, только чтение в BP
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Config")
    float MaxHealth = 100.f;

    // Реплицированное с callback
    UPROPERTY(ReplicatedUsing=OnRep_Health)
    float SyncedHealth;

    UFUNCTION()
    void OnRep_Health();

    // Не сохраняется, не сериализуется
    UPROPERTY(Transient)
    UParticleSystemComponent* SpawnFX;
};

Макрос UFUNCTION

UFUNCTION регистрирует метод в системе рефлексии: Blueprint может его вызвать, система сети генерирует RPC-обёртки, рефлексия позволяет вызывать по имени.

Спецификаторы UFUNCTION

  • BlueprintCallable — вызываемая из BP нода с execution pin.
  • BlueprintPure — без side-effect, нет execution pin (как геттер).
  • BlueprintImplementableEvent — объявлена в C++, реализуется в BP.
  • BlueprintNativeEvent — реализация по умолчанию в C++ (_Implementation), переопределяемая в BP.
  • Server, Reliable/Unreliable — RPC, выполняется на сервере.
  • Client, Reliable/Unreliable — RPC, выполняется на клиенте-владельце.
  • NetMulticast, Reliable/Unreliable — RPC на всех клиентах и сервере.
  • CallInEditor — кнопка вызова прямо из деталей редактора.
  • Exec — вызов из консоли командой имя функции.
UCLASS()
class AMyPlayerController : public APlayerController
{
    GENERATED_BODY()
public:
    // Вызов из BP
    UFUNCTION(BlueprintCallable, Category="Input")
    void StartSprinting();

    // Геттер в BP без execution pin
    UFUNCTION(BlueprintPure, Category="Stats")
    float GetHealthPercent() const { return Health / MaxHealth; }

    // RPC: клиент вызывает на сервере
    UFUNCTION(Server, Reliable)
    void ServerFire(FVector_NetQuantize Origin, FVector_NetQuantize Direction);

    // Реализация RPC (обязательный суффикс _Implementation)
    void ServerFire_Implementation(
        FVector_NetQuantize Origin, FVector_NetQuantize Direction);

    // Событие BP реализует — C++ только объявляет
    UFUNCTION(BlueprintImplementableEvent, Category="Events")
    void OnLevelUp(int32 NewLevel);

    // Консольная команда: MyExecCmd в консоли
    UFUNCTION(Exec)
    void MyExecCmd();
private:
    float Health = 100.f;
    float MaxHealth = 100.f;
};

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

  • BlueprintCallable на const-методе без BlueprintPure: const-метод в BP появится с execution pin; если нет side-effect — добавьте BlueprintPure для чистого геттера.
  • Отсутствие _Implementation у RPC: компилятор UHT генерирует декларацию _Implementation, но если вы её не определите — ошибка линковки с нечитаемым сообщением.
  • Replicated без GetLifetimeReplicatedProps: каждое поле с Replicated требует записи в GetLifetimeReplicatedProps через DOREPLIFETIME; без этого поле не реплицируется и нет предупреждения.
  • EditAnywhere на массиве UObject-указателей без UPROPERTY GC-спецификатора: поле и так попадает в GC через UPROPERTY, но если указатель не в UPROPERTY — редактор может отображать ссылку, а GC всё равно уничтожит объект.
  • Config без ini-раздела: поле с Config читает из ini только если в UCLASS указан Config=Game (или другой ini-файл); без этого значение игнорируется.
  • BlueprintImplementableEvent без реализации в BP: если BP-субкласс не реализовал событие, вызов из C++ просто ничего не делает — нет предупреждения в рантайме.
  • UFUNCTION(Exec) на не-APlayerController: Exec работает только на APlayerController, ACheatManager, AGameMode и AGameState; на других классах команда не регистрируется в консоли.

Common mistakes

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

What the interviewer is testing

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

Sources

Related topics

Что такое макросы `UPROPERTY` и `UFUNCTION` и какие параметры они поддерживают? | Talanto