System refleksji w Unreal Engine: Jak silnik obsługuje typy w czasie wykonywania
Unreal Engine wykorzystuje własny system refleksji do uzyskiwania informacji o typach podczas wykonywania. Pozwala to silnikowi serializować obiekty, wyświetlać właściwości w edytorze, integrować C++ z Blueprintami i zarządzać komunikacją sieciową. System jest zbudowany na generowaniu kodu poprzez Unreal Header Tool i dwóch równoległych hierarchiach typów.
Architektura refleksji: UHT i pliki generowane
Unreal Header Tool analizuje pliki nagłówkowe C++, znajduje makra takie jak UCLASS i UPROPERTY, oraz generuje kod do rejestracji typów. Ten proces tworzy dwa pliki:
- .generated.h — zawiera makra i deklaracje wstępne.
- .gen.cpp — obejmuje kod rejestracji typów, który może osiągać tysiące wierszy.
Wygenerowany kod przechowuje metadane, takie jak nazwy właściwości, flagi i przesunięcia w pamięci. Na przykład, dla właściwości CurrentValue w strukturze FAbilityAttribute rejestrowane jest jej przesunięcie przez STRUCT_OFFSET, co pozwala silnikowi bezpośrednio uzyskać dostęp do danych w runtime.
Dwie hierarchie typów: UObject i FField
W UE5 istnieją dwa systemy do opisywania typów, oddzielone dla optymalizacji wydajności.
Hierarchia oparta na UObject
Ta hierarchia jest zarządzana przez zbieranie śmieci i obejmuje:
- UClass dla klas C++.
- UFunction dla funkcji.
- UScriptStruct dla struktur.
- UEnum dla enumeracji.
Hierarchia oparta na FField
Wprowadzona w UE 4.25 dla zmniejszenia narzutów, właściwości tutaj nie uczestniczą w zbieraniu śmieci:
- FField — klasa bazowa.
- FProperty — opisuje poszczególne właściwości, takie jak FIntProperty lub FFloatProperty.
- Połączenie między hierarchiami: UStruct zawiera wskaźnik na linked list właściwości FField.
Kluczowe cechy FField:
- Używa linked list do przechowywania elementów podrzędnych.
- Zawiera FFieldClass z systemem szybkiego rzutowania typów przez maski bitowe.
- FFieldVariant łączy wskaźniki na UObject i FField, używając najmłodszego bitu do rozróżniania typów.
Anatomia FProperty: dostęp do danych
FProperty dostarcza mechanizmy do pracy z właściwościami w pamięci. Główne elementy:
- Offset_Internal — przesunięcie właściwości w pamięci, obliczane przez STRUCT_OFFSET.
- EPropertyFlags — flagi określające zachowanie, na przykład CPF_Edit dla edycji w edytorze.
- Metody dostępu, takie jak ContainerPtrToValuePtr, do bezpośredniego odczytu i zapisu wartości.
Przykład użycia:
UAbilityComponent* Comp = ...;
FProperty* HealthProp = Comp->GetClass()->FindPropertyByName(TEXT("HealthAttribute"));
FAbilityAttribute* HealthPtr = HealthProp->ContainerPtrToValuePtr<FAbilityAttribute>(Comp);
float CurrentHealth = HealthPtr->CurrentValue;
Praktyczne zastosowanie refleksji
System refleksji jest używany w różnych komponentach Unreal Engine:
- Seriałizacja — zapisywanie i wczytywanie obiektów z plików.
- Edytor — wyświetlanie właściwości w panelu szczegółów z obsługą kategorii i widżetów.
- Integracja z Blueprint — zapewnianie dostępu do właściwości i funkcji C++ z wizualnego skryptowania.
- Replikacja sieciowa — synchronizacja danych między klientem a serwerem.
- Zbieranie śmieci — śledzenie posiadania obiektów do zarządzania pamięcią.
Co ważne
- Refleksja w Unreal Engine opiera się na generowaniu kodu przez Unreal Header Tool, a nie na możliwościach C++.
- Podział hierarchii UObject i FField optymalizuje wydajność i zarządzanie pamięcią.
- Przesunięcia w pamięci, przechowywane w FProperty, pozwalają efektywnie uzyskiwać dostęp do danych podczas wykonywania.
- System wspiera kluczowe funkcje silnika, w tym serializację, edycję i komunikację sieciową.
- Zrozumienie refleksji jest niezbędne do opracowania złożonych systemów, takich jak komponenty umiejętności lub niestandardowe narzędzia edytorskie.
— Editorial Team
Brak komentarzy.