Hello everyone,
I am learning how to use Ue4 and just switched from Unity3D. My purpose here is to solidify my current understanding of modules (the documentation on this was a little vague), I would also like to discover some of the philosophy of good design for Ue4. Also sorry if i posted this in the wrong place I’m new here.
I would like to reiterate that this question is mostly philosophical in its nature, these are the following questions I would like to cover: How to use modules and load modules (is it loaded for you? or do I need to use a ModuleManager::LoadModulePtr("module");
, When to use modules? (I go more in depth about this later), How do you create modules? (Module Creation section demonstrates my understanding of the process), and more insight on the difference between modules and plugins.
I would like to make this as detailed as possible to help myself and others learn.
#Module Creation
Everything I found online in regards to Module Creation is either outdated or to vague to understand. So heres a short guide to module creation for ue4 4.16, this guide reflects the current state of my test project. Normally I wouldn’t have all of this cludder, but I was unable to find a single guide that was completely up to date with the current version of ue4 as of the date of posting this question.
Here is my understanding of the step by step process of creating a “Gameplay module” (if your learning modules this may be helpful), please correct me if I am wrong.
In the Ue4 documentation linked above, a module must contain “a header file (.h), C++ file (.cpp), and a build file (*.Build.cs)”.
##Setting up the module
Locate MyGame.uproject and add “MyModule” below to the Modules definition.
Here is what it should look like. (Sorry for the bad formating)
{
"FileVersion": 3,
"EngineAssociation": "4.16",
"Category": "",
"Description": "",
"Modules": [
{
"Name": "MyGame",
"Type": "Runtime",
"LoadingPhase": "Default",
"AdditionalDependencies": [
"Engine"
]
},
{
"Name": "MyModule",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"TargetPlatforms": [
"WindowsNoEditor"
]
}
This will set you up for a Runtime module or as they say in the docs “Gameplay Module”, if you want to create an editor module set the “Type” property from “Runtime” to “Editor” and also set the LoadingPhase property to “PostEngineInit”.
It is to my understanding that the Default LoadingPhase is loaded right after the game module is loaded. So for instance if you wanted to create a Loading Screen that actually does something useful then you would use the PreLoadingScreen LoadPhase option so that the loading screen happens before the game is already loaded.
Here is some more information about LoadingPhase.
##Creating the Module Folder Structure
I really wish this part was automated, but sadly it is not.
You will need to manually create the folder structure, cpp file, header file, and build.cs file.
First, locate your “Source” folder, then inside you should see “MyGame” folder create a new folder next to that and call it “MyModule” now cd to “MyModule”. Create two more folders and name them “Private” and “Public” respectively.
##Module Build Rules
You should still be in the “MyModule” directory, create a new file and name it “MyModule.Build.cs”.
Here is what “MyModule.Build.cs” should look like.
using UnrealBuildTool;
/// <summary>
/// Build module rules.
/// </summary>
public class Wire : ModuleRules {
public Wire(ReadOnlyTargetRules target) : base(target)
{
// Public module names that this module uses.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"MoviePlayer",
"Slate",
"SlateCore",
"InputCore"
});
// The path for the header files
PublicIncludePaths.AddRange(new string[] {"MyModule/Public"});
// The path for the source files
PrivateIncludePaths.AddRange(new string[] {"MyModule/Private"});
}
}
I added some extra private and public dependency module names to the list that are not necessary.
If you are wondering what the PrivateDependencyModuleNames
, and PublicDependencyModuleNames
does then click here.
Here is what MyGame.Build.cs should look like.
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class MyGame: ModuleRules
{
public MyGame(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "MyModule"});
PrivateDependencyModuleNames.AddRange(new string[] { "InputCore", "Slate", "SlateCore", "MyModule" });
}
}
I am not entirely sure if this is the correct way of doing this. In order for me to be able to reference “MyModule.h” from “MyGame” module I need to list it as a dependency. Then I use ModuleManager to load it
MyModuleClass* const module= FModuleManager::LoadModulePtr("MyModule");
I will also get an error if I try to directly use MyModuleClass. Using the loader seems to be the only way. I would imagine that there is another way to load and use a module, but I just haven’t figured it out yet.
##Editing Target.cs
Source is from here.
Go back to your source folder and inside there sould be a “MyGame.Target.cs” file and “MyGameEditor.Target.cs” file.
Here is the documentation.
Source/MyGame.Target.cs
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class MyGameTarget : TargetRules
{
public MyGameTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Game;
ExtraModuleNames.Add("MyGame");
ExtraModuleNames.Add("MyModule");
}
}
Source/MyGameEditor.Target.cs
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class MyGameEditorTarget : TargetRules
{
public MyGameEditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
ExtraModuleNames.Add("MyGame");
if (UEBuildConfiguration.bBuildEditor)
{
ExtraModuleNames.Add("MyModule");
}
}
}
According to this source it says to use OutExtraModuleNames.Add("MyModule");
, my guess is it’s outdated, unless i’m missing something.
If you take a look at the docs it says.
ExtraModuleNames (List<String>)
List of additional modules to be compiled into the target.
##Source Files
Source of tutorial here
Now we need to create a header and source file to get the module to compile.
Source/MyModule/Public/MyModule.h
#pragma once
#include "ModuleManager.h"
class MyModuleClass: public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
Source/MyModule/Private/MyModule.cpp
#include "MyModule/Public/MyModule.h"
IMPLEMENT_GAME_MODULE(MyModuleClass, MyModule);
void MyModuleClass::StartupModule() {
}
void MyModuleClass::ShutdownModule() {
}
Now that everything is setup, go into visual studio and rebuild the solution. MyModule should show up as a new filter in your solution explorer.
I have noticed that IMPLEMENT_GAME_MODULE(MyModuleClass, MyModule);
could also be written as IMPLEMENT_GAME_MODULE(MyModuleClass, "MyModule");
without any errors and the module still loads. However this breaks the launcher somehow.
#How Should Modules Be Used?
What goes into a runtime module?
When I think of module I think about frameworks. If I wanted to write a framework that is reusable with other projects should I use a module or plug-in? And to my understanding its okay for modules to reference engine code but not to reference Game code as that would lead to circular dependencies.
Another big question of mine is, should you let modules depend on other modules? I could imagine having a shared module that has some shared components that other modules use.
To my understanding a module is more specific to the game while a plug-in can be more widely used with other projects.
##How Do you Load Modules?
This is how I am currently loading “MyModule.h”
// Fill out your copyright notice in the Description page of Project Settings.
#include "TestComposition.h"
#include "ModuleManager.h"
#include "Engine.h"
#include "MyModule.h"
// Sets default values
ATestComposition::ATestComposition()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned. Testing only
void ATestComposition::BeginPlay()
{
Super::BeginPlay();
MyModuleClass* const module= FModuleManager::LoadModulePtr<MyModuleClass>("MyModule");
if (module!= nullptr)
{
module->StartupModule();
if (module->hello) {
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, "Module was successfully loaded.");
} else GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Failed to load Module.");
} else GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "The module manager failed to load Module.");
}
The module loads fine and StartupModule();
method simply sets hello to true. So my next step would be to give the api a singleton that gets instantiated in the StartupModule()
method. So then i could do module.GetSingleton();
. I would then use the singleton to get access to what ever manager or class I need through the api. Is this correct?
##Don’t Use Modules at All?
A simpler path would be don’t worry about modules, I mean they are hardly even mentioned anywhere unless were talking plug-ins. Do people use modules or is it something thats not worth using?
Sorry for the tower of text, I would be appreciative for some insight on these issues, thank you.