Improbable Icon

General Unreal Engine API feedback

unreal

#1

Hi. I’ve been working in Unreal Engine for over 3 years now, and have shipped a fairly big title. I just wanted to post some general feedback for the Unreal Engine API. I’m still digging into the system and understanding it, converting the DUSK demo into a FPS with most of the mechanics implemented in C++ as a starting point. I’m going to try to use this thread as a general dumping ground for my thoughts and ideas as I work through certain issues and then try to do things better.

The UE API has total callback overload. There are callbacks everywhere, and it forces a pattern that doesn’t sit well with most Unreal Engine programming. Namely that anything coming in over the wire needs to have dedicated functions to handle the remote data coming in, even when there is a component attached to an actor that is supposed to handle it.

It seems like it would be easier, from a C++ perspective, to be able to subclass the generated components and handle certain events. For example, I would love to have a MyTransformComponent that directly applies the transform updates to the actor it’s attached to. I could also set it to tick after the CharacterMovementComponent, allowing it to correct predicted positioning. By waiting for a callback, I can’t do this. My current solution is to create a second component (some UMyGameTransformComponent) that binds to the TransformInfo Component and handles it’s callbacks. This seems super messy, and some way to unify this process would be appreciated.

On that note, some more control over the code generator would be nice. I see little issues in the generated code (like creating a new UObject when a simple struct or TSharedPtr<> to a non uobject class could hold that data, decreasing GC load and improving performance) that could be improved.

On a higher level, there is a lot of boilerplate that seems like it could easily be handled by code generation. Unreal Header Tool can parse classes and generate boilerplate, which could really help with this. By modifying UHT, spatial could possibly leverage the Replicated UPROPERTY tag(or even create your own tag for Spatial) to spit out a schema for each object, and then set up the callbacks so that when new data comes in, it automatically sets the values in code… no boilerplate needed.

Also, I ran into an issue that after attempting a Hot Reload, some code was compiled into a .obj and then when trying to link later it gave linker errors for defining functions twice. I’m not sure what specifically caused it, but Hot Reload may be broken. To fix it, I cleaned out all of the generated code and then recompiled.


#3

Hey @RoyAwesome totally agree with most of your points. There’s a lot to be desired in the integration, and it certainly doesn’t feel natural in UE yet. I’m sure they will integrate with UHT soon and that might mean never having to run the spatial command outside of deployments.

As to replication, I totally agreed on your point a few months ago, but I’ve since come around. The hardest part of moving to spatial to me was dropping the client server bits of the gameplay framework in UE that you have to keep in your head (game mode, RPC, multicast, etc). I’m really surprised that most of these things just work out of the box.

That said, I think we could get by with a character subclass that integrates the core components as well. Transform, animation, etc.

Thanks for sharing!


#4

New thought (since I’m using this thread as a dumping ground for things I notice that are odd or dont seem to work right)… Why are Component Updates wrapped in a UObject?

Lets say I’m setting a position and rotation. I need to create an TransformInfo::Update object from the Improbable C++ API, then wrap it in a UTransformUpdate object, then pass it to the TransformComponent which then gets the underlying TransformInfo::Update object.

Why not just TSharedRef<> the raw update or better, pass the raw update object directly? This extra UObject doesn’t really have any use, especially in C++. For Blueprint, you could easily make a wrapping USTRUCT here, that way you aren’t putting undue pressure on the Garbage Collector by spawning a UObject that is almost immediately thrown away.


#5

Digging in even more, this time through the SpatialOSGameMode

Why is connection state handled in the GameMode? This seems better handled in the GameInstance, which is a singleton object that lives through the entire lifecycle of the process. It’s relatively painless to derive from UGameInstance, add in a bunch of code, and then make the .ini change to get the engine to use your custom class. Also, since you are doing a bunch of Asset loads, placing these tasks in a custom GameInstance seems like a better place to do it. This is generally where I put Online services and the like.

Binding of UE Object Classes to Spatial Entities seems really… messy. Unreal Engine has an object, FStringClassReference that takes any given class path and has a member function TryLoadClass<T>(). You can Construct one of these off of any give Path, store them (Maybe using a TMap<int32, FStringClassReference>?), and then use them to reference entity objects. This probably works better in the long run, as the FStringClassReference works for both C++ and Blueprint classes.


#6

Hey @RoyAwesome,

Thanks so much for taking the time to write up these great points - your feedback really is invaluable to us :slight_smile:

You’ll be pleased to hear that some of these things have already been implemented in our next SDK release (such as using UGameInstance as our persistent data store) and we’ve done quite a lot of work to improve the quality of the Unreal integration specifically.

The number of wrapper classes and excessive allocations is something that is on our minds and that we’ll be looking to improve going forward. As you mentioned, a lot of these issues come down to the need to expose objects and properties to Blueprints, but there’s certainly a lot of room for improvement. The amount of boilerplate code is also something that we’re aware of and are looking to improve - as ever with SDK design, it’s a case of providing sensible default behaviour that doesn’t force or constrain developers to an unnatural structure.

Thanks again for these notes - keep 'em coming! :support:

Patrick


#7

I’ve been doing a lot of digging into the GameplayAbility framework that is included as a Plugin in UE. They actually tackle a very similar problem to what Spatial has, where you have some ‘struct-ish’ object that can’t really be exposed to BP but needs heavy Blueprint interaction.

They solve it by using a struct handle that only exposes the type to BP, then uses a BlueprintFunctionLibrary to create the functionality for it. It kinda works. It might be worth digging in there and using some of those patterns.


#8

Digging into the Snapshot creation code now. I’m using the DUSK demo, and I really don’t like how it’s hardcoded.

So, fun fact… in the header markups (UPROPERTY, UCLASS, etc), there is a Meta tag that can contain any key/value pairs. If you get the Class and look up it’s properties (through UE’s reflection system), you can look up any of those tags, allowing for any custom markup you need.

I’m writing some code right now to load a given map, loop through all of the objects in the scene, and then write out snapshots for the snapshot commandlet. Should be fairly game neutral (as long as the game developer uses the proper meta tags).

I’ll see if I can use this to replicate properties as well, might be a fun project.


#9

Would love to see what you come up with there Roy. :slight_smile: I believe the SpatialOS guys where also looking into doing something similar in the future (low priority item atm I imagine) so they might be interested also if its fairly game neutral.


#10

To follow up on one of the original points is there any eta on when a plugin will be available so that we are not locked in to a specific build of Unreal so that we can actually look at getting it integrated into our project?