Constructor called twice


#1

I am spawning a pawn in a world, and I noticed that its constructor is being called twice: Once when I declare and bind it in SK, and the other when I ‘spawn’ it in the game world.

I am wanting to override the BP defaults with custom settings, but I cannot touch these them when the constructor is first called since these references are null (I presume because it hasn’t spawned in the game world, UE4 hasn’t initialized the object’s memory). Having to “wait” until the second constructor call is too late, since I want these defaults overriding UE4’s, and by this point the object is now created.

I feel as though I am playing with fire here. Any suggestions?


#2

You do need to be careful with what you do in the constructor. Because there isn’t any guarantee as to when it fires, it could be the actor coming into the world for the first time, it could be a temporary object being created.

If you’re trying to make sure certain variables are set before BeginPlay fires on the actor then usually the pattern you would use is to deferred spawn an actor, set variables and then finish spawning.

e.g.

!c : GameLib.begin_deferred_actor_spawn_from_class(,some_class, some_transform, ESpawnActorCollisionHandlingMethod.@@adjust_if_possible_but_always_spawn)
c.@some_var := 1
c : GameLib.finish_spawning_actor(c, some_transform)

#3

Thanks!

Am I safe to call begin / finish spawning in the constructor? Or would you recommend that I separate that out into its own method?


#4

Generally no since the game world might not exist yet. It would be better to do this on BeginPlay.


#5

Thanks. I’m trying to use on_begin_play, which tells me via comment to override the method in my subclass, but I’m not seeing any documentation on how to do that. How does that work?


#6

This isn’t wired. So you’ll actually need to call some custom &blueprint annotated function from the blueprint’s BeginPlay.


#7

I see. Thanks!


#8

I got around to trying this and have run into a snag. I think my conceptual model is off somewhere.

I have an actor blueprint with an integer variable whose default value is 7. I have a :sk: method called Init that prints it out on Event BeginPlay.

:sk: does, eventually print out 7, but only after raising an exception about an issue with offsets (see pictures below). My guess is that, by the time BeginPlay is called, :sk: has not yet learned either what this variable’s value is or where it is laid down in memory – is that true? If not, then it seems like a buggy behavior.

As discussed above, my intention is to set these kinds of actors up with information defined in :sk: by working around the constructor issues. But before I set anything up, I ran this simple test to see if :sk: could see these variables at BeginPlay, and the answer seems to imply no, at least not how I am trying to.

And yes, I neurotically saved and compiled twice over to better ensure I wasn’t dealing with a cache sync issue.

sk1


#9

Can you clarify what “eventually” means in this context? Does it mean:

  • When you hit play a 2nd time things work?
  • When you hit ignore things work
  • There’s some other call to @init that later succeeds?

As an experiment, in your BP_SK_INIT_TEST blueprint, can you try adding a SkookumScriptClassData component, compiling and testing this again.


#10

By “eventually” I meant, at least, when I pressed “Retry”. I tried no other option so it may be true for those cases as well. Sorry for the ambiguity.

For some reason, it’s no longer throwing an exception this morning without making any changes or without restarting the editor. I’ll have to try to repo it again next week and report back with more specifics if possible.

But what I’m doing, or at least trying to accomplish, should in theory just work, right?


#11

Yes. But there was a bug I recently fixed that exists in 4.18 that could explain this. There’s a class component that can be added to any actor called SkookumScriptClassDataComponent. This component creates the :sk: data instance. Back around the 4.16 era, you’d have to manually add one of these components to any actor that you wanted to use :sk: with.

Later on in 4.17 or 4.18, a mechanism was added whereby this component was automatically added to actors. Unfortunately, there were a couple edge cases where the component would not get added, sometimes in packaged games, sometimes when doing odd things in the editor. So back when I was just a consumer of the sdk like yourself, my mantra was that anytime I saw a class that seemed to exhibit being unable to find their data instance, I’d manually slap on a SkookumScriptClassDataComponent and problem solved.

Since then I’ve made a few patches that I believe fix these edge cases but there hasn’t been a public release that includes them yet.