C++ Integration
Module Setup and Dependencies
The PhotonFusion plugin ships three modules.
Module |
Type |
Description |
|---|---|---|
| PhotonFusion | Runtime | Available on every supported platform — this is the module customer game modules link against. |
| PhotonFusionEditor | Editor | Hosts the editor customization and debug tooling and is stripped from cooked client builds. |
| PhotonFusionBlueprintNodes | UncookedOnly | This module holds Fusion-specific Blueprint nodes. |
PhotonFusion.Build.cs re-exports the engine modules it depends on — Core, Engine, DeveloperSettings, PhysicsCore — so a downstream module that lists PhotonFusion does not need to repeat them.
The FUSION_BODY Macro
FUSION_BODY() is declared in FusionMacros.h and placed in a UCLASS or USTRUCT body immediately after GENERATED_BODY(). It mirrors the way Unreal's own generated-body macros work — a per-class anchor that the code generator hangs the generated body off.
C++
#include "MyActor.fusion.h"
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
FUSION_BODY();
UPROPERTY(Replicated)
float Health;
};
The .fusion.h Generated Header and Build-Tool Integration
The PhotonFusionUbtPlugin is a C# UnrealHeaderTool exporter, declared as FusionUhtCodeGen. It runs alongside UHT during the standard Unreal build and emits two files per header file: <Name>.fusion.h (which FUSION_BODY() expands into) and <Name>.fusion.gen.cpp (which carries the implementations).
The exporter registers two new UHT keywords via FusionUhtKeywords. FUSION_BODY records the macro line number per class. SEND_FUSIONRPC parses the RPC function declaration that follows it, synthesises a <Name>_Receive companion declaration plus a hidden __FUSIONRPCEVENT_<Name> UPROPERTY, and generates the dispatch glue in the .fusion.gen.cpp.
What the generators output.
| Input | Generator | Output |
|---|---|---|
MyClass.h |
UHT (stock) | MyClass.generated.h + MyClass.gen.cpp |
PhotonFusionUbtPlugin (Fusion UHT exporter) |
MyClass.fusion.h + MyClass.fusion.gen.cpp |
The SEND_FUSIONRPC Macro
SEND_FUSIONRPC(...) is a sentinel keyword. In C++ it expands to nothing — FusionMacros.h defines it as #define SEND_FUSIONRPC(...); — so the compiler sees an unannotated function declaration. The UBT plugin, however, parses the macro as an RPC declaration and generates the dispatch glue. The compiler and the code generator effectively see two different things, which is how the plugin avoids adding any compile-time overhead to call sites.
C++
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
FUSION_BODY();
SEND_FUSIONRPC(EFusionRPCTarget::SendToObjectOwner)
void MyRpc(int32 Damage, FVector Location);
// Developer implements this on the receive side:
void MyRpc_Receive(int32 Damage, FVector Location);
};
For the higher-level RPC semantics, and reliability/ordering guarantees, see RPC Basics.
Inlining Macro
Starting from unreal version 5.8 the generated *.gen.cpp files are no longer scanned automatically when unreal compiles the project. In order to have fusion generated files work properly a macro must be added right after the header declarations in the implementing .cpp file. The naming should be the HeaderName + fusion separated by a .. Including this macro in earlier versions of unreal will also work for backwards compatibility, but it's not neccessary.
C++
#include "MyClass.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(MyClass.fusion)
Type Descriptors
UFusionTypeDescriptor (in Types/FusionTypeDescriptor.h) is the runtime metadata Fusion builds for each replicated class or struct. Fusion uses it internally to build the buffers for encoding data to send over the wire.
UFusionFunctionDescriptor is the RPC sibling. It describes how to encode/decode the arguments when sending and receiving data.
Fusion networks properties in a linear word buffer. The descriptor tracks all the networked properties and their sizes. The following is a list of some common sizes of properties when scanning a replicated object. Structs are compound objects and are internally built up of the lowest common simple type.
Type |
Word Size (Word = 4 bytes) |
|---|---|
Byte |
1 |
Int / UInt |
1 |
Int16 / UInt16 |
1 |
Int64 / UInt64 |
2 |
Float |
1 |
Double |
2 |
Vector |
6 |
Rotator |
6 |
Quat |
8 |
String |
2 (String pointer, string is in a network heap) |
ObjectId |
5 (Variable, holds either network object id or string pointer) |
Array |
Variable (element_size * preallocated_elements) |
Custom |
Defined by the custom descriptor builder |
Custom Type Descriptor Builders
UFusionCustomTypeDescriptorBuilder (in FusionCustomTypeDescriptorBuilder.h) is the override point for type descriptors. Subclass it and override CreateDescriptor(UFusionTypeLookup*, UStruct*, FProperty*, FPropertyBuildOptions) to return a hand-built UFusionTypeDescriptor instead of the reflection-driven default. This is how Fusion implements its own special-cases — FFusionNetworkedArray and AGameStateBase both ship custom builders.
Register the builder with UFusionTypeLookup::RegisterTypeBuilder(UStruct* Target, UClass* Builder). The plugin itself does this in UFusionOnlineSubsystem startup for FFusionNetworkedArray (via UFusionNetworkedArrayBuilder) and AGameStateBase (via UFusionGameStateDescriptorBuilder).
C++
UCLASS()
class UMyDescriptorBuilder : public UFusionCustomTypeDescriptorBuilder
{
GENERATED_BODY()
public:
virtual UFusionTypeDescriptor* CreateDescriptor(
UFusionTypeLookup* Lookup,
UStruct* Target,
FProperty* SourceProperty,
FPropertyBuildOptions Options) override
{
// Build a custom descriptor and return it.
}
};
// In module startup:
UFusionTypeLookup::RegisterTypeBuilder(
FMyData::StaticStruct(),
UMyDescriptorBuilder::StaticClass());
How Replicated Properties Are Found
Similar to Unreal's own networking solution, Fusion will scan for properties marked with Replicated or ReplicatedUsing. These properties are then added to the UFusionTypeDescriptor for the type being scanned.
Defining a GetLifetimeReplicatedProps is not necessary when using Fusion, but porting over an existing type will still work fine and the method is simply not used. All of this can be overridden with a custom type descriptor when more control over replicated properties is needed.
Customizing Replicated Arrays
Fusion pre-allocates the array size when building the descriptor for a type, it will default to reading DefaultArraySize from Fusion settings. If another size is required please use the FusionArraySize metadata on the UPROPERTY. Note that there is a maximum capacity cap of 64 elements for networked arrays.
C++
#include "MyData.fusion.h"
USTRUCT()
struct FMyData
{
GENERATED_BODY()
FUSION_BODY()
UPROPERTY(EditAnywhere, Replicated, meta = (FusionArraySize = 24))
TArray<int32> Array;
};
Back to top