sinbad / SPUD

Steve's Persistent Unreal Data library
MIT License
308 stars 45 forks source link

SpudSystem Initialization #25

Closed shoooxz closed 2 years ago

shoooxz commented 2 years ago

Hello, What is the best way to add PersistentGlobalObjectWithName, for example GameInstance object or setting up Model. When I add it on GameInstance event init, I am keep getting warning: LogScript: Warning: Accessed None trying to read property CallFunc_GetGameInstanceSubsystem_ReturnValue Seems like SpudSystem is not initialized at this point, as I understand first is initialized GameInstance and then All Subsystems Inializations. Where I should place all init functions? Thank You, Regards

ps. I am trying to achive this in blueprints

shoooxz commented 2 years ago

I was testing a bit, and when I'm editing GameInstanceExample from your examples, I see that on Event Init also exists the same problem:

LogScript: Warning: Accessed None trying to read property CallFunc_GetGameInstanceSubsystem_ReturnValue BP_SpudExamplesGameInstance_C /Engine/Transient.UnrealEdEngine_0:BP_SpudExamplesGameInstance_C_7 Function /Game/FirstPerson/Blueprints/BP_SpudExamplesGameInstance.BP_SpudExamplesGameInstance_C:ExecuteUbergraph_BP_SpudExamplesGameInstance:00CC LogBlueprintUserMessages: [BP_SpudExamplesGameInstance_C_7] 0

Adding object on the parent level (cpp object) with Super:Init() works good, saving etc,

shoooxz commented 2 years ago

I managed to fix this with cpp class parent which use BlueprintNativeEvent (ovverride in bps) function triggered after Super:init, hope this is acctualy good way of doing this :)

sinbad commented 2 years ago

FWIW I've been using AddPersistentGlobalObjectWithName in our game instance's Init() function without any issues so far. However, I notice in the ELoadingPhase docs that Default, which is what SPUD uses, is "during engine init, after game modules are loaded."

I always thought game modules were loaded after plugins in Default but apparently not. I'm not sure why I haven't been bitten by this yet.

I think I should probably change SPUD's LoadingPhase to PreDefault instead to make sure the subsystem is guaranteed to be there for game module init.

sinbad commented 2 years ago

I managed to fix this with cpp class parent which use BlueprintNativeEvent (ovverride in bps) function triggered after Super:init, hope this is acctualy good way of doing this :)

Actually this is why I haven't seen it in our game. Looking at the documentation, the ordering of loading isn't actually the issue, it's ordering of subsystem Initialize. Because SPUD is registered as a UGameInstance subsystem, it will have its Initialize called as part of the UGameInstance::Init function. That's guaranteed to happen irrespective of LoadingPhase.

So I think the problem you had was that you didn't call the parent Init function. In Blueprints, you still have to do this if you override a function. So you didn't need to go to C++, you just needed to right-click the Init event and select "Add call to parent function", and wire it up:

image

shoooxz commented 2 years ago

I was testing this, and still SpudSystem Subsystem is not valid.

sinbad commented 2 years ago

Huh, you're right. This makes no sense - in my C++ UMyGameInstance::Init, I can call GetSpudSubsystem(GetWorld()) and the SPUD instance is valid. Yet in a Blueprint subclass of this very C++ class, in Event Init after calling the C++ parent implementation which uses SPUD successfully, the value returned from the Blueprint Spud Subsystem node is not valid.

I can only conclude that it's something to do with the way BPs are hooking up the GetWorld part, because there's no reason this shouldn't work. I guess it's just best to do all your UGameInstance::Init work in C++.

shoooxz commented 2 years ago

I think I should probably change SPUD's LoadingPhase to PreDefault instead to make sure the subsystem is guaranteed to be there for game module init.

Shall I change LoadingPhase to PreDefault in plugin then ?

sinbad commented 2 years ago

No, that doesn't help, I already tried it. As I found in the documentation, it's not the loading that's the problem, it's something wrong with how the Blueprint version of GameInstance's Init doesn't have everything constructed yet. It's a Blueprint problem, since a C++ superclass has no issue in this same method.