UClass
Containing information
-
- Name
-
The name of an UClass not only names it but also gives base information about its usage. Such name has one character based prefix.
U
describes the use as a normal UObject.A
describes the use as an Actor in a scene. + f.e.UClass
,UTutorialObj
andATutorialBuilding
-
- Class Flags
-
This is a flag register about typical stats of a class like if it’s abstract or if its visible to the BP VM.
-
- Cast Flags
-
This is a flag register describes to which basic unreal types a
UObject
of thisUClass
is castable to.
Building
Building is the most complex thing in the BPI cause there are just so
many parameters which need to get set properly. The beginning makes the
SML::Paks::ClassBuilder
-Builderclass in assets/BPInterface.h
This builder class is a bit special because it has a template which
should be your class you want to reflect. The builder class will
automatically use the native name of your class to call
name(std::string name)
Your native class name should due to this contain a |
Example:
class UDocClass {}
SML::Paks::ClassBuilder<UDocClass>::Basic();
as you can see you need to use the Basic()
function to get the
proper ClassBuilder reference. It’s just a reference because this class
builder needs to exist all the time and works like a singleton and this
Basic()
function just initializes the singleton with a basic setup
and returns the reference to the singletons instance.
Flags
You can define class flags, like if it should be visible, with the flag
functions. addFlag(SML::Objects::EClassFlags flags)
,
addFlag(int flags)
and
removeFlag(SML::Objects::EClassFlags flags)
are used to help
defining the class-flag-register. The same principle applies to class
cast flags but with the classes f.e. addCastFlag(...)
Extending
You need to explicitly tell the builder which reflected superclass your
class has (even if it’s just the basic UObject). To make this easier the
builder class implements two functions which take each of them a class
type to execute their StaticClass()
functions. If you don’t want to
do this through templates you can also use the
superFunc(UClass*(*classFunc)())
and pass a function pointer
returning the UClass of your superclass.
yeah ik, it’s weird, but hey! It makes it more easy to use! And if you
don’t like it, you can just use superFunc(UClass*(*classFunc)())
Unreals reflection system does not support multi inheritance like c++ does, that means you can’t use the extend function twice to have two classes inherited, instead you would probably just overwrite the old one. |
Example:
class UDocClass : public SML::Objects::UObject {}
class ADocActor : public SDK::AActor {}
SML::Paks::ClassBuilder<UDocClass>::Basic().extend<SML::Objects::UObject>()
SML::Paks::ClassBuilder<ADocActor>::Basic().extendSDK<SDK::AActor>();
Attributes
Attributes (aka. member-variables) which need to get reflected get
defined with the param(SML::Paks::PropertyBuilder builder)
function.
Simply pass the unbuilt PropertyBuilder to this function and it gets
reflected. If your property needs an offset value and you didn’t
manually provide a value, automatically the last available/defined
offset gets used. Also, the last available/offset gets increased by the
size of the given property. The first param uses the size of the
superclass as the offset.
That means the order is important! But you can rearrange or completely ignore the order by explicitly setting the offset value in the property builder. The last available/defined offset gets automatically set to the previous property offset + size.
For examples please refer to UProperty
Functions
Functions (static and member) which need to get reflected get defined
with the func(SML::Paks::FunctionBuilder builder)
function. Pass
this function the needed FunctionBuilder and it will get registered.
Interfaces
Because Unreals reflection system doesn’t support multiple inheritances like we know it doesn’t mean there is no. Unreal uses interfaces to implement this concept but without any private functions or member variables.
To declare the implementation of an interface you will need the
implementInterface(UInterface* interface, size_t offset)
function.
Simply pass this function the UInterface
and the offset to the
vtable-pointer referring to the interface implementation in your class.
The Interface support is very, very difficult because the SDK currently
doesn’t provide the information needed to implement this. Only some
interfaces are written into SML (like |
Example:
class UDocClass : public SML::Objects::UObject, public SML::Objects::ISaveGame {
virtual bool shouldSave() overwrite { return true; }
}
SML::Paks::ClassBuilder<UDocClass>::Basic()
.extend<SML::Objects::UObject>()
.implementInterface(SML::Objects::ISaveGame::staticInterface(), (SML::Objects::ISaveGame*)(UDocClass*)nullptr);
Constructor
The constructor of a BPI generated class is very special. We cant use
the normal constructor because that one wouldn’t call the right
constructors of the child classes. That means you need to explicitly set
the constructor to member-function of your class with declaration
void constructor()
(name not important) and call the
constructor(void(BuildClassT::*)())
to define it. Because we can’t
use the C++ constructor here (even not the default one) we would need to
call the constructors or define them by our self.
You need to know that the BuilderClass generates a second internal one which manages the pointers, superclass construction and much more, but you’re able to define your own one if you desire to. (We do not recommend that) |
Destructor
The destructor works just like the constructor. But important to note is
that you need to call the destructor on every member which needs that.
And you need to use the destructor
function to define it.
Do not delete the members here! They get (automatically freed by the reflection system! Just call the destructors if needed. |
Example (destructor & constructor):
class UDocClass : public SML::Objects::UObject {
float testNum;
std::string testString;
void constructor() {
testNum = 0.0;
new (&testString) std::string();
}
void destructor() {
testString.~string();
}
}
SML::Paks::ClassBuilder<UDocClass>::Basic()
.extend<SML::Objects::UObject>()
.constructor(&UDocClass::constructor)
.destructor(&UDocClass::destructor);