Types

Uncover the inner workings of the Atomix Plugin's Architecture.

One of the most challenging issues we faced when designing Atomix was type reflection. More specifically, Unreal Engine's Reflection system.

Unreal Engine's reflection system is genius and innovative. It allows us as developers to design and implement almost anything we desire and have that Reflected in edtior for us to use with ease.

However that is only half of the equasion. Unreal is fantastic at providing us with a reflection system that can be used for Types in C++ and have them accessable in BluePrints. But it lacks the backwards compatibility for types created in BluePrints to have them reflected in C++ we can reference.

This is not the end of the world. Infact we gain more by having our Types reflected by Unreal.

Example Reflected Struct

FExampleStruct.h
/* This is a very basic example of what a component might look like. */

USTRUCT(BlueprintType) 
struct FExampleStruct {

  GENERATED_BODY(); 

  UPROPERTY(BlueprintReadWrite, EditAnywhere)
  FName ExampleName {NAME_None};

  uint8 ExampleAge {0}
}

Example Non-Reflected Struct

FExampleStruct.h
/* This is also a very basic example of what a component might look like. */

struct FExampleStruct {

  FName ExampleName {NAME_None};

  uint8 ExampleAge {0}
}

In C++ both will function identically, however we lose much of the functionality affored to us by reflecting the struct with Unreal. When we define it like the second example we no-longer have access to the StaticStruct traits which allows us to not only view the struct in editor. But also any networking support offered by Unreal Engine.

You can probably see where this is going.

If you DON'T need your types to be replicated then the general rule of thumb is that you can use them with Atomix without registering them. However if you wish to replicate a component then you must register it.

Why should you care?

Honestly, it's not that interesting for the majority of people. But if you do then continue reading.

Given that our platform is built atop ENTT, we have to 'get with the program' so to say. In ENTT types must be known at compile time, and passed as type arguments to ENTT's methods. Great! you might be saying, C++ is a compiled language, what's the issue. Well if you would let me explain I will get to it.

We cannot pass types to ENTT directly from BluePrints. BluePrints use the class UScriptStruct to expose C++ struct types to Unreal's Editor. However there is not a way to get a C++ type from it. So you could pass in a UScriptStruct to a BluePrint Node and that passed to a native function, but when the C++ type is needed, you're out of luck.

Hence Our Reflection System

Atomix's reflection system doesn't aim to reinvent the wheel. It simply provides a way for Atomix to get type information at runtime from a C++ type or a UScriptStuct. Each component (type) is registered with Atomix and assigned an ID. This ID is the same for every player, server or user provided it is initialized in the correct way. (See the setup page)

This affords us the ability to take a UScriptStruct and turn it into the corrorsponding C++ type. This also helps with replication in many ways, but that is outside the scope of this page.

The only caviat is that the type must originally be defined in C++, it cannot be a BluePrint type of struct.