Download

Adding modding support to my game

Hello everyone,

A lot has been written on the topic of modding, but a lot of it out of date. I’m working on a tower defense game and I’m looking to add modding support so that players can create their own towers for instance.

It seems there were recent efforts to create a plugin to supposedly make adding modding support easier through the SimpleUGC plugin (Inside Unreal: Adding Mod Support with the Simple UGC Plugin). However, this requires a source build of the engine to recompile the AutomationTools. This is a distant second option to me. I would very much prefer to stick with the launcher-provided binaries, not to mention the pain and horror I see going around on the internet trying to migrate an existing project to a source build of the engine.

I am also aware of the blog post by Tom Looman (https://www.tomlooman.com/unreal-engine-mod-support-example/) which outlines how to add a mod as a new plugin. I can see how this would work for DLC that I would personally create, but how do I ship the editor to players such that they can create this plugin? I would naively think that I just ship all my development files but I would also be giving away my entire source code and all assets for anyone to rebuild or reskin my game completely and without much effort. That can’t be the way it’s intended.

Additionally I understand there is the EULA to be considered, but the SimpleUGC approach would also require you to ship the editor so I assume there are possibilities to get it legally arranged. Right now I’m only interested in getting this working technically.

Can anyone point me in the right direction here on how to add modding support to my game?

Having migrated a few, I don’t see why youd have any issues migrating to source build providing the engine version is the same.
In fact, most of them just ended up opening and working directly with a few nasty exceptions.

I guess the question is what kind of mod are you expecting to be produced.
A whole level needs different kind of access than creating a custom asset, for instance.

You can take a page from Ark - they tell you get the engine, and here is how you produce stuff and here is where you place it in the game folder.

At a base level - all mods - are tied to the executable of the game reading the contents of a folder and making use of them.
You can write this in c++ in under 10 minutes.

How you use what contents you read, that’s a deeper discussion. If it’s literally just a mesh, and correlated textures, you could even go as far as hot loading an FBX and the textures into a material instance dynamic.

If you wanted to create an internal tool, that’s a different story…

Thanks for the insights @MostHost_LA! I guess I should clarify indeed. I’m looking for a very basic level of modding for now. I will only involve subclassing a single Blueprint and implementing a few virtual functions. I have the logic for reading all subclasses of this Blueprint from the AssetRegistry implemented.

What puzzles me is how I can get the editor in the hands of a modder, so that they have this base Blueprint available to subclass, without putting all the unrelated assets (other meshes, materials, audio, etc.) in their hands as well.

I took a look at Ark and it seems like they are simply putting their entire project up for download, minus maybe the C++ sources, I couldn’t tell. Is that indeed the intended road to go down? Put the project basically up for download and have modders create plugins from that?

I wouldn’t go that far.
The problem with the editor is licensing. You need them to have an epic account and DL from epic to avoid issues with that.

You have to govern what they can produce in editor that the mod support of the exe will then look for in the actual game.

I’d try and limit the result to a Pak file so you can use the built in dlc system.

The engine is really anything but secure. Anyone can unpack your game files and extract whatever / modify it, re-pack it, substitute it, and run the game that way.

You can probably use the same idea based on what you describe you need.

So thanks to your pointers and a few days of experimentation and trail-and-error further, I have something which works to my liking! I can create a new plugin in the editor, generate a Pak-file, and have the game pick it up automatically just by placing the Pak-file in the correct folder. Awesome, thanks a lot!

I’m still fuzzy on the final piece of the puzzle, which is getting my editor in the hands of potential modders. I get that there is the license to consider, but right now I’m just interested in understanding how to complete the puzzle technically.

Assuming that my potential modders have the launcher and Unreal Engine installed, what do I put up for download so that they can open up an editor of themselves, create a new Blueprint derived from one I provide, and build it as Pak-file to drop in my installed game’s content folder?

2 Likes

I would zip up a sample project they can load onto the appropriate installation/project folder directory and launch from.

If you made a plug in, you may need to include that separately.

As far as licensing, there’s usually no concern from sharing a project folder.
Just make sure it doesn’t mistakenly include template files from the engine to be extra safe (but those templates are commonly avaliable for the specific purpose of being shared, so there is usually no concern).

For packaging plugins, just follow the marketplace guidelines to be safe. (It’s a lot of unnecessary mambo jambo tbh)

Could you share your findings? I’m working on a similar problem. I started with the SimpleUGC example, but like you, want to be able to simply provide a project that can be used with the user’s own editor to build the mod, without needing a custom engine installation.

My two challenges right now are:

  1. How to build a Pak without building AutomationTool from source? It looks like I can execute UAT with BuildCookRun and do the same thing if I have the right arguments that I can assemble using the ProjectLauncher and looking at the logs. Is that the same technique you are using?

  2. How to load the Pak at runtime? Right now I am still mostly following the SimpleUGC example, so my UGC is a plugin that goes in the Mods directory. It contains a uplugin file alongside a cooked and packaged Content directory. It’s being picked up by the PluginManager, but the map I have in it doesn’t seem to be picked up by the AssetRegistry.

Hi @ryan_skyglass,

I didn’t use the SimpleUGC example so I cannot comment on that. I basically departed from a guide written by Tom Looman a long time ago (Add Mod-support to Unreal Engine 4 Projects - Tom Looman).

When my game starts, I use a bit of C++ code to discover classes derived from a certain input class. In my case, this is the base class which defines a tower:

#pragma once

#include "CoreMinimal.h"

#include "AssetRegistry/AssetRegistryModule.h"
#include "Kismet/BlueprintFunctionLibrary.h"

#include "MyBlueprintFunctionLibrary.generated.h"

UCLASS()
class MY_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:

	UFUNCTION(BlueprintCallable)
	static TArray<UClass *> DiscoverClasses(UClass * BaseClass);

private:

	static IAssetRegistry & GetAssetRegistry();
};
#include "MyBlueprintFunctionLibrary.h"

TArray<UClass *> UMyBlueprintFunctionLibrary::DiscoverClasses(UClass * BaseClass)
{
	IAssetRegistry & AssetRegistry = GetAssetRegistry();

	FARFilter Filter;

	Filter.bRecursiveClasses = true;
	Filter.bRecursivePaths = true;

	Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());

	TArray<FAssetData> Assets;

	AssetRegistry.GetAssets(Filter, Assets);

	TArray<FName> BaseClassNames;

	BaseClassNames.Add(BaseClass->GetFName());

	TSet<FName> ExcludedClassNames;
	TSet<FName> DiscoveredClassNames;

	AssetRegistry.GetDerivedClassNames(BaseClassNames, ExcludedClassNames, DiscoveredClassNames);

	TArray<UClass *> DiscoveredClasses;

	for (auto const & Asset : Assets)
	{
		FAssetDataTagMapSharedView::FFindTagResult GeneratedClass = Asset.TagsAndValues.FindTag("GeneratedClass");

		if (!GeneratedClass.IsSet())
		{
			continue;
		}

		FString ClassPath = FPackageName::ExportTextPathToObjectPath(*GeneratedClass.GetValue());

		UClass * DiscoveredClass = LoadObject<UClass>(NULL, *ClassPath);

		if (DiscoveredClass == BaseClass)
		{
			continue;
		}

		if (!DiscoveredClassNames.Contains(*DiscoveredClass->GetName()))
		{
			continue;
		}

		DiscoveredClasses.Add(DiscoveredClass);
	}

	return DiscoveredClasses;
}

IAssetRegistry & UMyBlueprintFunctionLibrary::GetAssetRegistry()
{
	FAssetRegistryModule * AssetRegistry = &FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));

	return AssetRegistry->Get();
}

I then simply loop over the results and add them to the user interface.

As to actually creating a mod, I create a new project-specific plugin. I then simply build this plugin and place the resulting Pak-file into the appropriate direction for the main game. It will get picked up automatically and will be available in-game.

I have not gone full circle yet by zipping up the project and creating a plugin elsewhere, but at this point I am willing to believe that works :slight_smile:

I hope this helps!

Thanks for the detailed explanation @Laurens!

Where do you put the pak file in order for it to be automatically picked up? Do you have to build your plugin from the game project (meaning you will have to ship your full game project to mod creators) or can you create it from a separate project?

This is what I got working yesterday, in case it helps anyone:

I have two Unreal projects, BaseGame and ModKit. BaseGame has custom code and assets; ModKit is completely empty except for an editor module (derived from SimpleUGCEditor) that adds buttons to the editor for creating and packaging mods.

Importantly, ModKit’s .uproject file is actually called BaseGame.uproject. This appears to be required to get BaseGame to pick up plugins packaged for ModKit later.

To create a new mod, I simply create a new plugin in the “Mods” directory of ModKit. I use the “Create UGC” button from SimpleUGCEditor to create the plugin, although as currently written, it adds AdditionalPluginDirectories": ["Mods"] to the end of my ModKit’s .uproject file which I have to remove to avoid errors about including the same plugin twice.

To package the mod, instead of using the “Package UGC” button from SimpleUGCEditor (since it requires building AutomationTool from source), I used this approach:

  1. Package the ModKit as a game itself, either using the “File > Package Project” menu, or creating a new ProjectLauncher configuration (see Tom Looman’s guide referenced above).
  2. Copy Metadata and AssetRegistry.bin from ModKit\Saved\Cooked\WindowsNoEditor\BaseGame to ModKit\Releases\<version name>\WindowsNoEditor (this is in the UGCExample guide)
  3. Use Tom Looman’s technique (creating a DLC build configuration) to figure out the correct command line arguments to pass to <UE>\Engine\Builds\BatchScripts\RunUAT.bat BuildCookRun. (See “Command Line” at https://docs.unrealengine.com/4.27/en-US/SharingAndReleasing/Deployment/BuildOperations/_ for a discussion of using ProjectLauncher to figure out BuildCookR arguments.) In my case, the command that is working so far is:
.\RunUAT.bat BuildCookRun -project=path/to/ModKit/BaseGame.uproject -noP4 -nocompileeditor -targetplatform=Win64 -cook -pak -dlcname=MyFirstMod -DLCIncludeEngineContent -basedonreleaseversion="1.0.0" -compressed -stage -package -archive -archivedirectory=/Staging/ModKit/1.0.0 -clientconfig=Development -serverconfig=Development

I will be iterating on those arguments today to figure out which ones I really need/want.

This builds and packages my mod to /Staging/ModKit/1.0.0/WindowsNoEditor/BaseGame/Mods/MyFirstMod. I built BaseGame separately to /Staging/BaseGame/1.0.0, then copied the MyFirstMod folder to /Staging/BaseGame/1.0.0/WindowsNoEditor/BaseGame/Mods.

In my base game, I include the UGCRegistry code from UGCExample to find all the mods and any maps they contain. Currently I iterate over all mods and maps and load the first map I find. This is working.

So with this technique it looks like I don’t need to share BaseGame with mod creators, as long as ModKit’s project is actually named BaseGame. If I named ModKit’s .uproject file ModKit.uproject, BaseGame will see the mod, but it doesn’t seem to load the map into the asset manager.

Here is the UGC Example for anyone who needs it (requires Epic Games GitHub membership—Unreal Engine 4 on GitHub - Unreal Engine). https://github.com/EpicGames/UGCExample/blob/release/Documentation/QuickStart.md

This is the code for finding all the mods: https://github.com/EpicGames/UGCExample/blob/58eaa3207c283a07227cd62da03f2ec4167c0705/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp#L16

And this is the code for finding all maps within a mod: https://github.com/EpicGames/UGCExample/blob/58eaa3207c283a07227cd62da03f2ec4167c0705/Plugins/SimpleUGC/Source/SimpleUGC/Private/UGCRegistry.cpp#L67

Hope this is helpful for someone!

The way I understand it now it does require you shipping your project. I’m still a little baffled by it as well, but I do not currently see any way out of it. I build the plugin from the game project indeed, and then place the resulting Pak-file in the Content folder of the main game (WindowsNoEditor/MyGame/Content/Paks).

OK that makes sense. For what it’s worth I was able to get it working in a standalone mod kit project so I don’t have to ship my base game project.