I started with the Multi-threading example(using FRunnable) from @Rama’s tutorial. I chose the 3rd person character sample project. I managed to make the multi-threading work with this project(ie. run a task on a non-main thread in background, while I control the character in MainThread). The FRunnable implementation was in a new class inheriting FRunnable as illustrated in the tutorial. This worked. Note that - this project by default has only one module - primary game module.
Now comes the problem. I wanted to have this multithreading support in another module, but in the same project(ie. not in a plugin). So, I created a new project module, with the standard Public, Private, .Build.cs files.
Now, if I implement the module using IMPLEMENT_MODULE(), the thread (FRunnableThread) is not being launched. However, if I implement this module as IMPLEMENT_GAME_MODULE(), it works!
So, what and why does it work with IMPLEMENT_GAME_MODULE() and not with IMPLEMENT_MODULE()? Really appreciate if someone can clear this.
From what I understand, there should be only one primary game module per game project. However, I’m not sure of what modules should be implemented as a game module and what shouldn’t. Also, for a plugin module, can we do IMPLEMENT_GAME_MODULE? How should I decide/think when I’m doing this?
Also, the source code comments use “gameplay code” to indicate whether it should be a gameplay module. What does gameplay code mean?
If you think my code will help to answer/discuss, let me know and I can show it here.
A game always needs to have one Primary Game Module. That’s the core module you would put your main game code into.
After that every other module that doesn’t depend on the Primary Game Module can and should be just a normal module.
If, however, one of your modules depends on your Primary Game Module (or any other game modules) then it should be a game module, which sets up hot-reloading support as far as I understand it. I talk briefly about this in my UE4 Modules presentation.
You usually don’t have modules depending on your primary game module, so this should be a very rare case (an exception would for example be a module with tests that depend on your primary game module’s code). Your dependencies should usually be structured like a tree, to avoid cyclic dependencies.
I don’t know why it’s only working for you when the code is in a IMPLEMENT_GAME_MODULE instead of IMPLEMENT_MODULE, I’ve used FRunnableThread in many normal non-game modules before without issues.
I suggest the issue might be elsewhere. You need to consider when is the thread supposed to be launched. In case it’s a module lifetime issue, you might not be adding your module to the .uproject file correctly. Or your module might be missing from the compilation dependency chain if your Primary Game Module doesn’t depend on it.
@Flassari, thanks for your reply! As it appears, it is not to do with IMPLEMENT_GAME_MODULE or IMPLEMENT_MODULE. I had created the thread wrapper as a static object and hence did not work as expected the second time due to its active lifetime. I have the following follow up questions:
The module’s LoadingPhase determines when the module is loaded. What happens during this loadingPhase? (For eg, is the module’s startupModule() called during this time?).
Can anyone give examples of when ‘PreDefault’ should be used and not ‘Default’ or similar differences where a wrong one might completely not make the module work?
What is the lifetime of a module? When is the shutdownModule() called?
For eg, when I start my project in editor mode, a module is loaded if loadingPhase is let’s say ‘Default’. I can see that module’s startupModule() is called when editor starts. Now, I start my game and end it. I don’t see shutdownModule() being called. Does this mean shutdownModule() is called when I close the editor?
How do I control the lifetime of a module? ie. let’s say I want to start/load the module when my game starts and end the module when my game ends.
What is hot-reloading? Where can I find more information on it? (I can’t seem to find any info on when and how it is used/called)
Yes, the module is loaded into memory, its main class is instantiated, and then StartupModule in the main class is called.
I suggest to always try to make it work on ‘Default’ if you don’t have a strong and obvious reason not to. If you have 5 modules but they all depend on one other module to be loaded before them all you could make that dependency module load before all of them in the PreDefault phase for example, but I’d suggest instead to have the other modules just call FModuleManager::Get().LoadModuleChecked on any module they depend on.
A module can startup when either:
• The engine starts, according to the module descriptor’s loading phase in the .uproject or .uplugin file.
• The user activates a plugin that contains the module.
• Earlier if another module loads it by manually by calling FModuleManager::Get().LoadModuleChecked<FFooBarModule>(TEXT(“FooBar”)).
A module will shut down when either:
• The Editor (or your cooked game binary) is shut down.
• The plugin it’s in gets disabled.
The module is alive until either your cooked game binaries are closed, or if using the editor, until the editor is closed. It doesn’t follow the lifetime of a game session, it follows the lifetime of the application that loaded it. I would recommend you DON’T try to override a module’s lifetime yourself. That’s not really how they’re supposed to work. If you want something to follow the lifetime of a game session I suggest adding a GameInstance subsystem class to your module.
Hot reloading is what the editor does when you press the Compile button in the editor. It will compile your code and then “hot reload” the modules of it back into the editor without you having to restart the editor. Here’s a community wiki on Hot Reloading and Live Coding.