BPVM Snack Pack #11 - Linking and Binding: The Final Assembly | ebp BPVM Snack Pack #11 - Linking and Binding: The Final Assembly | ebp BPVM Snack Pack #11 - Linking and Binding: The Final Assembly | ebp
Post

BPVM Snack Pack #11 - Linking and Binding: The Final Assembly

After creating properties and functions, they're just loose parts. Linking and Binding connects everything together into a working class. Here's the final assembly line.

BPVM Snack Pack #11 - Linking and Binding: The Final Assembly

The content in this post is based on Unreal Engine 5.6.0

BPVM Snack Pack - Quick Blueprint knowledge drops! Part of the Blueprint to Bytecode series.

The Scattered Parts Problem

After compilation, you have:

  • Properties created ✓
  • Functions generated ✓
  • Memory allocated ✓

But they’re not connected. It’s like having all car parts but no assembly!

The Two-Step Assembly

Unreal uses two operations to connect everything:

1
2
3
4
5
// Step 1: Find the C++ connections
NewClass->Bind();

// Step 2: Link all the properties
NewClass->StaticLink(true);

Think of it as:

  1. Bind: Connect to the engine (find the steering wheel)
  2. StaticLink: Connect internally (wire the dashboard)

Bind(): Finding the C++ Functions

Bind() searches for three critical things:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void UClass::Bind()
{
    // 1. Find the constructor
    ClassConstructor = FindConstructor();
    // "How do I create instances?"

    // 2. Find VTable helper
    ClassVTableHelperCtorCaller = FindVTableHelper();
    // "How do I set up virtual functions?"

    // 3. Find static functions
    ClassCppStaticFunctions = FindStaticFunctions();
    // "What C++ functions can I call?"

    // Recursively bind parent class
    if (GetSuperClass()) {
        GetSuperClass()->Bind();
    }
}

It’s like finding the instruction manual for your class!

Why Bind Matters

Without Bind(), Blueprint can’t:

1
2
3
4
5
6
7
8
// Can't create instances
AMyActor* Actor = NewObject<AMyActor>();  // No constructor!

// Can't call parent functions
Super::BeginPlay();  // No VTable!

// Can't call static functions
AMyActor::StaticFunction();  // Not found!

Bind() creates the bridge between Blueprint and C++!

StaticLink() creates the property linked list:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void UStruct::StaticLink(bool bRelinkExistingProperties)
{
    // Link all properties into a chain
    FProperty* Previous = nullptr;
    for (FProperty* Prop : Properties) {
        if (Previous) {
            Previous->Next = Prop;
        }
        Prop->Offset = CalculateOffset(Prop);
        Previous = Prop;
    }

    // Calculate total size
    PropertiesSize = 0;
    for (FProperty* Prop : PropertyLink) {
        PropertiesSize += Prop->ElementSize;
    }
}

Before: Properties exist but don’t know about each other After: Properties form a linked list with calculated offsets!

Memory Layout Calculation

StaticLink() figures out where everything lives:

1
2
3
4
5
6
7
8
9
10
// Before StaticLink
Property: Health (?)
Property: Armor (?)
Property: Name (?)

// After StaticLink
Property: Health  Offset: 0x0000 (4 bytes)
Property: Armor   Offset: 0x0004 (4 bytes)
Property: Name    Offset: 0x0008 (16 bytes)
Total Size: 0x0018 (24 bytes)

Now the engine knows exactly where each property is in memory!

The Reference Chain

Properties can reference each other:

1
2
3
4
// During StaticLink
FObjectProperty* MyActorRef;
MyActorRef->PropertyClass = AMyActor::StaticClass();
MyActorRef->LinkInternal();  // Connect to the class!

This creates the web of references between objects!

Parent Class Recursion

Both operations work recursively:

1
2
3
4
5
6
7
8
9
// Bind() goes up the chain
BP_MyActor::Bind()
   AActor::Bind()
     UObject::Bind()

// StaticLink() does too
BP_MyActor::StaticLink()
   AActor::StaticLink()
     UObject::StaticLink()

Every level of inheritance gets properly connected!

The Alignment Magic

StaticLink() also handles memory alignment:

1
2
3
4
5
6
7
8
// Optimize for CPU cache
if (Property->Size == 1) {
    Alignment = 1;  // Bytes can go anywhere
} else if (Property->Size <= 4) {
    Alignment = 4;  // Align to 4 bytes
} else {
    Alignment = 8;  // Align to 8 bytes
}

This makes your Blueprint faster at runtime!

The Final Connection

After both operations:

1
2
3
4
5
6
7
8
// Everything is connected!
Class {
    Constructor:  (found by Bind)
    VTable:  (found by Bind)
    Properties:  (linked by StaticLink)
    Size: 0x0018  (calculated by StaticLink)
    Alignment: 8  (calculated by StaticLink)
}

Your class is now a fully functional machine!

Real-World Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// You create a Blueprint with:
float Health = 100;
int32 Armor = 50;
AActor* Target;

// After Bind() and StaticLink():
BP_MyClass {
    Constructor  AMyActor::AMyActor()  // Found!
    Properties  [
        0x00: Health (float, 4 bytes)
        0x04: Armor (int32, 4 bytes)
        0x08: Target (AActor*, 8 bytes)
    ]
    Total Size: 16 bytes
    Property Chain: HealthArmorTargetnullptr
}

Quick Takeaway

  • Bind() finds C++ functions (constructor, VTable, statics)
  • StaticLink() connects properties and calculates memory layout
  • Properties become a linked list with offsets
  • Memory is aligned for performance
  • Both work recursively through inheritance
  • Together they transform loose parts into a working class!

The Assembly Complete

When compilation finishes with Bind() and StaticLink(), your Blueprint class is no longer a collection of parts - it’s a fully assembled, ready-to-run machine with every wire connected and every bolt tightened!

Want More Details?

For the complete linking process:

Next: Understanding the statements that become bytecode!


🍿 BPVM Snack Pack Series

This post is licensed under CC BY 4.0 by the author.