Problem with plugin versioning - plugins won't load on second copy built from same source

This is driving me batty. Been working on it for a week now and I simply have no clue what is going on.

We have two builds of our engine. One for developers (the dev build) and one for artists (the artist build). Both are built from the exact same GitHub source, but the artist build had a bunch of un-needed files removed such as source code, pdbs, etc in order to trim down the size on disk.

The artist build was built from the same source and distributed to artists a few months ago. The dev build is what we are using to develop our pipeline plugins with. The problem though is when we try to take those plugins developed using the dev build and copy them to a project in the artist build the project no longer works, as it complains that the plugin is incompatible or not found. This happens regardless of if the plugin is placed into a project’s plugin folder or the engine’s plugin folder.

I really don’t even know where to start on trying to fix this. I’ve quadruple checked everything to be certain that I am building from the proper source, with the proper build targets.

As I said both builds of the editor are built from the same GitHub source, the only difference between them is some trimmed out files and the fact that the dev build has been built more recently, but again from the same source.

Even if I don’t use a project, if I just copy the plugins into the engine’s plugin folder and run the editor directly I get the same error.

While we have 4 or 5 plugins, this issue is not unique to any one. Any one by itself will cause this error.

John,

It sounds like the problem you’re having is that the UE4Editor.modules file is either misnamed, not present, or invalid.
This is the file that points out to the engine what binaries to use for a given plugin (really, any module).

This file should be located in the Binary output folder for plugins.
For example:

/MyProjects/Plugins/SomePlugin/Binaries/Win64/UE4Editor.modules

This is what a sample one from our Flurry plugin (that we distribute from the engine) looks like:

{
	"Changelist" : 3201819,
	"CompatibleChangelist" : 0,
	"BuildId" : "4d964985-9390-4882-a5ca-0455359f9e57",
	"Modules" : 
	{
		"FlurryEditor" : "UE4Editor-FlurryEditor.dll"
	}
}

Here are a few common issues I’ve seen that can cause issues:

  1. The file has the Platform / Build type encoded in the name, such as UE4Editor-Win64-Debug.modules. In this case, just rename the file.
  2. The module points to the wrong / non-existent DLL. This can cause undefined behavior, including what you’re seeing or random crashes.
  3. The Changelist / BuildId are incompatible (due to the engine being newer than the plugin, or vice versa). In this case, the best approach is to recompile the plugin. However, if you’re sure that the Plugin should be compatible with a given engine version, you can just replace these values with those found in any other working module / plugin. This is not recommended as it may cause issues in the future, but can work as a short term hack.

Thanks,
Jon N.

The “BuildId” field is designed to ensure matching binaries for local builds of the editor, where you may have any number of local changes which break API compatibility, and there’s no other authoritative way to qualify whether binaries are built from the same source code. We randomize it to ensure that there are no collisions when, say, binaries are submitted to revision control, but developers are also rebuilding them from source in the same workspace.

If you’re making a formal build from a specific set of code, you can version them explicitly instead. This is what we do for the binary UE4 releases, and our internal engine builds created by our build system. We use Perforce at Epic, so it’s based around the changelist number being the unique id, but you can set it to any monotonically-increasing 32-bit integer you like. If you want to disable these checks entirely, you can just hard-code it to a specific non-zero number.

The number is stored as “Changelist” and “CompatibleChangelist” in Engine/Build/Build.version. You may create a build from one changelist that’s compatible with an older build which is why there are separate values; both need to be set. Also set “IsLicenseeVersion” to 1 in the same file, so that the engine knows how to deal with content from Epic which has our changelist numbers baked into it.

You’ll also need to compile the same numbers into the engine binaries by modifying BUILT_FROM_CHANGELIST in Engine/Source/Runtime/Launch/Resources/Version.h. This file has a comprehensive explanation of how the system works in the comment at the top.

As a side note, I’ve created a ticket for this as you’re not the first to have seen this issue: UE-38783.

There’s no guarantee as to when the fix will be in place, so please use the above workaround until then.

Thanks,
Jon N.

Thanks for the reply Jon. It looks like the BuildID is the issue. Do you know how this is generated? Is it just given a unique ID each time you build the editor? If so then that would explain the issue. Even though they are both built from the same source, the developer copy has been rebuilt a few times.

We’ll have to try and work out a way to keep the BuildIDs synced somehow I guess.

John,

I could be wrong, but I think it may just be random. Generally, I would expect that if the plugin isn’t rebuilt (because dependencies haven’t changed) then it shouldn’t rebuild.

However, depending on what you called out in your plugins dependencies, I’m not sure how great it is at actually determining whether something important has actually changed.

Thanks,
Jon N.

Well the problem is that the plugins are in active development, so yeah that get rebuilt all the time. The artist build was put into our local software installer months ago and we just update the plugin versions as new work is done. So this is a bit of a pain because each time we update the plugins now we have to go in and edit the file before release. It would be nice to have an option to avoid that. Yeah we are rebuilding them and working on them but the underlying engine code isn’t changing.

John,

Unfortunately, I’m not sure if disabling the version checks would be something we’d want to do internally (even optionally). The whole point behind them is to ensure the plugin and other modules are always up to date.

Consider what would happen if you updated an API in the plugin that also required mods to separate game / editor module. If you just distribute the plugin and there’s no check, then it’ll try to load and the Editor will crash (probably with little to no useful logging). However, if you distribute the plugin and check, at least you’d see that they were out of sync and you’d have the option to disable the plugin (and as long as it’s non-critical, it wouldn’t be a big deal).

Further, plugins are really just treated as modules. That means they go through the same code path as all other modules (like Core / Runtime / Editor) when they’re loaded. With the issues above, this would cause some pretty big headaches.

You’d have to do a couple of things:

  1. Add some sort of flag to modules which actually identified them as plugins vs. non-plugins.
  2. Compare your version check argument against whether or not it was a plugin, and then skip it.

Although this wouldn’t necessarily be that hard, it does have the potential to break some pretty core functionality and the value it adds is minimal (in most cases).

Thanks,
Jon N.

Oh I completely understand the point of the checks, but like I said in our case the problem is that the editor isn’t changing, so why would the plugins not work? We are essentially going to be hacking the system by changing the buildID by hand I guess, but it just feels wrong. Problem is we can’t rebuild the entire editor and redistribute a new copy to the artists every time we want to update the plugins, and it would be pointless anyway since the build would be the same except for some magic identifier.

I guess we’ll just have to hack it by changing the GUID each time.

John,

It’s not just the editor version. You also have to think about your project version and your project code.

When you think about it, the dependency chain is like this:

The Engine relies on nothing but internal modules.
Plugins rely on nothing but the Engine.
Projects rely on the Engine, and may rely on Plugins.

So, you’re right, as long as the engine doesn’t change you shouldn’t need to recompile plugins. The caveat here is that this only holds true as long as you’re only creating new projects. As soon as you create a project however, that project establishes a dependency on a specific plugin version.

You have 2 options at this point to ensure consistency. You can either enforce that the project be rebuilt or the plugin be rebuilt.

Now, just going off of how normal dependency chains work, it would make sense to say that your project needs to be rebuilt.

However, projects are a bit more open ended. First, they may or may not actually have code (like BP only projects). Second, if they do have code, chances are there’s far more of it than of Plugin code, and therefore would take longer to compile and be harder to distribute. Third, plugins are more transient in that it’s sort of expected a project was created locally (relative to an organization anyway) whereas there’s no real expectations about plugins (for example, we sell plugins on our marketplace but don’t sell projects).

All of that said, I do agree that having to change generated code manually isn’t an ideal solution, and that maybe there are better ways in which the checks can be done to avoid some of that.

Thanks,
Jon N.

Thanks for this info Ben, very interesting. We are migrating our plugins to 4.14 next week so I will look into this to see if we can improve the experience for our artists.

I think we are somewhat unique in that we don’t produce project/game builds, we ONLY use the editor.