How to design a game using modules and Ue4 Design Patterns

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.

You seem to have a pretty good understanding of the system. A few points.

First off, there is not really anything special about the initial game module, it’s just that by default code projects will have a single module with the same name as the project, but that isn’t necessary. I think the only difference is that there must be exactly one module in a project implemented with the IMPLEMENT_PRIMARY_GAME_MODULE macro. There’s nothing I know of that must be different in the Build.cs file of that module as compared to any other.

When you add a dependency using *DependencyModuleNames.Add(), these are static dependencies. That means the dependency module will be loaded automatically when the module referencing it is loaded. Modules listed in the .uproject with any LoadingPhase other than “None” will also be loaded at project startup I believe. Anyway, with static dependencies, you are able to use any publicly exposed classes and methods from the module, so there is not really any need to get a reference to the module class itself.

The alternative is dynamic loading. You specify the dependency via DynamicallyLoadedModuleNames.Add(), along with a matching entry in PrivateIncludePathModuleNames. Then you expose an interface of virtual functions which you inherit your module class from, and get access to it from another module via FModuleManager. This is a bit more work and isn’t always what is wanted, but it allows you to reduce coupling between modules, and also implement plugin-like behaviour where you can search for modules at runtime and carry on/bail out smoothly if the module isn’t found.

The ExtraModuleNames in the target file is rarely needed - generally there will be a chain of dependencies from your first game module which will lead to other modules being included automatically.

Don’t call StartupModule yourself, that is done by the engine. Also if you’re not going the dynamic loading route, you probably don’t need to bother defining the module class. It’s enough to simply put this in a cpp file:

IMPLEMENT_GAME_MODULE(FDefaultModuleImpl, MyModuleName);

It’s completely fine for one game module to reference another, though of course you should avoid circular dependencies.

I don’t have time to go into plugins right now, but I think this might be a good topic to cover in more depth on my website, so if I get around to writing an article I’ll come back here and link it.

In “Target.cs” I removed ExtraModuleNames.Add("MyModule"); and the game still compiled (MyGame was still able to reference MyModule’s public classes). So its to my understanding that MyModule is included because of the MyGame/MyGame.Build.cs more specifically PublicDependencyModuleNames.AddRange(new string[] { "MyModule" });.

In the documentation it specified that ExtraModuleNames.Add is a

List of additional modules to be compiled into the target.

I’m not entirely sure what this means, but I think I have an idea of what it might be doing. (Thanks for pointing that out)

If the engine calls StartupModule, then I shouldn’t need to call MyModuleClass* const module = FModuleManager::LoadModulePtr("MyModule"); or is this the dynamic loading route you talked about before?

So if I understand this correctly, if I where creating a loading screen, I could create a module that loads before the main game module and control would be given to the loading module through StartupModule.

Furthermore, a module could be a collection of public classes and thus the Module class would not be needed (The class that inherent’s from IModuleInterface). However you must define MyModule.h and MyModule.cpp because at minimum those two files including the build.cs file are required for the module to load properly.

Thank you for taking your time to answer my questions.

Yep, startup module will always be called by the engine when a module is loaded, regardless of what triggered it to be loaded.

All the variants of the LoadModule methods are meant for use with dynamic loading. You can call it on a module that is a static dependency, but by definition it will already be loaded, so it will simply behave like FindModule and give you a reference to the existing module class instance.

Strictly, the minimum requirement for a module is just the build.cs, plus a cpp file containing the IMPLEMENT_MODULE macro. And yes, if you just want to expose public classes, or types to be used only in editor/blueprint, then there is no need for a module interface.