Hitching despite loading asset async?

To preface my system predates GAS and no I’m not going to redo it for the sake of using GAS.

Ok, with that said I’ve an ability system using actor components. Abilities can apply effects (e.g. burn dot, poison dot, etc..), which are also actor components. All of this is using async load class asset. None are using blocking loading.

I’m applying a burn dot, which atm has no visuals, and is just an actor component with a timer applying damage. That’s it. On first application it causes a hitch. Once that first application has spawned the hitch is gone.

The process is: Async Load Class > Cast to Actor Component > Add Component to Actor

Does anyone have any clue why it’s doing this? Shouldn’t the async load class have dealt with loading this in properly? Is there anything more I can do here to stop this hitching? It can’t be shader compilation as there’s no visuals here.

Hi Krileon,

What you’re seeing is normal. Even with async loading, the first time you spawn a component, Unreal still runs initialization code (vtable setup, reflection, etc.), which can cause a hitch. Pre-instantiating or “warming up” the component early in the game usually removes this first-hit hitch.

1 Like

I tried my best to come up with a solution other than “warming up” components, but I guess it’s unavoidable since even Fortnite suffers from the same hitches.

Yeah, but wouldn’t “warming up” still cause the hitch as it’d still have to be spawned in or am I misunderstanding how to “warm up” the component. I might be fine with that approach to get rid of this as it’s just not good experience for players.

Couldn’t find a solution. The async load asset is already handling loading what it can into memory smoothly, but the AddActorComponent node still causes hitching even for an empty actor component. There has got to be something that can be done about this. If anyone has any ideas I’m all ears.

Did you try capturing the hitch in Unreal Insights?

Just points to the AddActorComponent call. So I assume it’s the act of initializing it, but I can’t find a way to stop this. Even an empty actor component causes a stutter. It’s a small one, but it’s still a stutter. I’ve no idea how to improve this.

you’d have to use pooling i think, but i don’t think you can pool actor components? This is why GAS and other systems use UObjects. Still ive not experienced hitching from ACs, theyre pretty lightweight, are you sure thats the issue?

Yeah, it’s the AC. I’m firing off 10 projectiles that hit 10 different enemies. On enemy hit it adds an AC to them. The hits aren’t all in the same frame so it’s not a situation of adding 10 AC in a single frame.

I think I’ve more or less eliminated it though. I’ve an Effects component attached to these enemies that tracks the effects on them. This was just casting to AC instead of casting to BPAC_Effect. So changed that over to allow my base class to just always exist in memory since it’s always going to anyway. This has helped a good bit. It’s strange though as I would’ve assumed AsyncLoadAsset would handle any kind of hitching like this, but I guess there’s more to it than just async loading it in.

If the AC’s will eventually exist anyway, more or less, just add them by default and have the hit enable them.

That might be an idea here. How do Timers work in BP Objects though? I’ve never tried doing that to be honest. I can just throw them into a map variable of Tag => Object, but I’ve no clue if their timers would work lol.

Ok, experimenting converting these to BP Object instead of BP Actor Component. I don’t need replication so don’t need the ease of AC replication. I also don’t need Begin/EndPlay as these are all manually handled from a parent controlling AC with BPI function calls. Timers do work fine as long as you using the construct object from class and keep a reference (I already do). These should be a bit more lightweight than an actor component.

Seams mostly doable converting to BP Object, but running into a snag with AsyncLoadAsset.

image

There’s no pin to connect world context, lol.

That’s mainly because UObjects are created without a World Context and Async Load Asset requires one. Not sure if you can address issue with only BPs, but you can definetively do it with C++.

Yeah there’s no way to do it without making a new base class in C++ extending UObject just with WorldContext support. Just going to stick with the ActorComponent implementation for now. I’ve at least reduced the stutter substantially by ensuring the base actor component is always loaded into memory so that’s good enough for now.