Unreal Tip - Modifying Replicated Properties On The Client
- Details
- Category: Articles
This was fun. I was looking into a plugin that wasn't behaving as expected, particularly around an array of structs that was being replicated. Scanning through the code, the problem became obvious quite quickly. The author had a TArray of UStructs on the server, that was being manipulated on the server, and replicated to clients. So far, so good!
On the client however, the author had an OnRep function that executed on replication, which read the entries in the array and did some logic, and then deleted the contents of the array. The comments in the code indicated that the author was attempting to use the replicated array as a network message queue of sorts, where new or modified entries get added on the server, processed on the client when it's replicated, then removed from the queue.
This is not how replicated arrays work! The replication system attempts to keep the state of properties in sync between server and client. This is quite straightforward with single structs, but with arrays, it uses the array index to track and serialise dirty properties that need replicating. For this to work, the replication system needs to know that the state of the array on the client is consistent. So when item at index 5 is modified on the server, we really need to be sure that same item is still at index 5 on the client! If we do what this plugin does, and modify the property on the client, at the same time as the replication system is trying to send and apply change deltas to the client, we're going to have a really bad time. We may be replicating properties on an entirely different array element, or even out of bounds.
Don't Modify Replicated Properties On The Client
The solution to this is simple : Do not ever, ever, modify replicated properties on the client.
When you mark a property as replicated, you are saying to the engine, 'keep this property in sync with the server'. If you don't want it to be in sync with the server, then do not use property replication.
If you are modifying a replicated property on the client, it stands to reason that you want to read that value again at some point. With a replicated property, you have absolutely no idea when that value is going to be overwritten by the replication system, it's a recipe for expensive, intermittent bugs and many wasted hours debugging.
Unreal Tip - Common UStruct Issues
- Details
- Category: Articles
I've been meaning to start using the site more, quite a lot of work to maintain it these days, needs a big Joomla upgrade, so use it or lose it! With that in mind, I'm going to be starting to post little nuggets of (hopefully) wisdom, and some longer articles, all game dev, AI, and Unreal related. So...first up...a code smell. I've been having to work with some less-than-expertly written plugins recently, and have done a lot of bug fixing, many of which can be easily avoided by identifying common issues.
Common UStruct Issues
This is a pattern that I've seen cause issues many times. There are no compile or run time warnings when you do this, so it isn't obvious when you have a problem.
USTRUCT()
struct FThing
{
UPROPERTY()
float Foo;
float Bar;
}
There are a few things wrong here which we should think about.
Uninitialised Members
Neither member variable is initialised, however, the Unreal property system will assign a default value to Foo. Bar will be junk.
Non-UPROPERTY Members
Only one of the members is marked as UPROPERTY. This isn't automatically an issue, but why is the member Bar not UPROPERTY? Usually when you create a UStruct, you want to create a data object that is exposed to the reflection and blueprint system....having some data exposed in this way, and some not, I'd be wanting to know a good reason why this is the case, and check it's not an oversight.
What's The Problem?
Imagine you're working on a multiplayer title, you're sending a FThing from server to client with an RPC and using it to drive some game logic. But what the hell? I've set Bar to X on the server, and when it's replicated to the client, it's Y? Well, the reason is simple, Bar is not a UPROPERTY, so it isn't serialized. When the struct is replicated, the new FThing is constructed, Foo is set to default by the property system, then set to the replicated value, but Bar is neither initialised, nor deserialised, it it's value could be anything, so you have this new FThing on the client which appears to have replicated correctly, but one of the members is a randomly wrong value! Cue much head-scratching.
Unreal Tip - Profiling in Unreal Engine 5 with PIX
- Details
- Category: Articles
Just a small FYI post here, as I wasted a bit of time figuring this out recently.
My profiling tool of choice is Pix For Windows, which I've been using for years on UE4 projects. Hooking it up was simply a matter of enabled the console variable
Stat NamedEvents
This has not been working in UE5, since Early Access, and didn't work in 5.0 release either. Anyways, I had a poke through the engine code and realized Epic had refactored the way external profilers are handled. You now need to add the following command line option, to use Pix.
-PIX
I hope this saves some people a bit of head-scratching!
January 14th 2022
- Details
- Category: Site
Just a little update, I've been doing some poking around in UE5 and done the necessary housekeeping of all my plugins, so they're all running fine in UE5 now. Just a few minor compatibility changes required.
There's a few warnings that I'll fix once 5.0 launches, but I don't really want to maintain a separate branch just for them.
In other news, I will be starting a new job in March.....details TBA :)
Page 5 of 25