UE多用户协同编辑服务部署指南

In the context of the large-scale project and the remote working demand caused by the pandemic, collaborative editing under development has become particularly important. In UE’s resource mechanism, maps are single resources; although they can be split using the Sub-level format, the smallest element remains a single resource. When different designers modify the same resource, it can lead to file conflicts, and merging is not as straightforward as with text. Furthermore, when each person is responsible for editing a single sub-level, there is no way to preview the entire scene’s effect in real-time, which is a bottleneck in collaborative development.

After UE4.23, UE officially launched a multi-user collaboration mechanism that allows multiple people to edit the same map simultaneously without causing conflicts. It can also synchronize other changing resources and take effect in real time. As a supplement to version control, it effectively resolves issues of synchronized collaboration.

This article records the enabling process, usage specifications, network strategies, and other issues. It will also extract an independent server-side program without relying on the complete engine, allowing for convenient deployment of the server side.

UE’s official multi-user editing is implemented as a C/S architecture solution. Official documentation: Multi-User Editing

Essentially, it creates a server process to manage the multi-user editing sessions and transmit changing data between multiple clients. Each session represents one “room” for collaborative editing, and only those who join this “room” can preview and synchronize other people’s submissions in real time. Multiple sessions can be created on each server, which can be created and joined by different users.

Note: UE does not directly copy the changing resources to each client but achieves the same performance by transmitting the changing data to each client. This approach is more efficient in terms of data transmission, but there is a problem: for resources with the same operations, the uasset may not be completely identical. For instance, if user A modifies Weapon.uasset, the changing data will be synchronized to user B. If both A and B submit the Weapon resource, their binaries will not be exactly the same, leading to conflicts during the merge process. Submission specifications still need to be noted.

Usage Process

Multi-user editing support relies on UE’s Multi-User Editing plugin:

After enabling, you can see the Multi-User Editing and Multi-User Transactions options in Project Settings-Plugins:

Multi-User Editing

Multi-User Transactions

You can configure parameters for multi-user collaboration.

Once the plugin is enabled, you can see the Multi-User Browser option in the editor under Windows-Developer Tools (you can also enable Enable Multi-User Toolbar Button in Project Settings-Plugins-Multi-User Editing):

After startup, it will automatically search for visible UnrealMultiUserServer servers in the network:

Multi-User Browser

You can also launch an UnrealMultiUserServer process locally by using Launch a Server. Typically, there will be an independent machine serving as the server for other users to connect.

Multi-User Browser connects to the server as a client using the UDP protocol, with a default connection port number of 6666 (the default for Launch a Server is also 6666). You can modify it to specify another port number, and the client will automatically detect the list of reachable servers in the network to choose from when creating a session.

Launch a Server

Note: Multi-User Browser relies on the UDP Messaging plugin for network transmission, so if we want to change the default connection port number, we need to modify the default port number in UDP Messaging.

You can modify it in Project Settings-Plugins-Networking (change 230.0.0.1:6666 to 230.0.0.1:XXXXX):

Note: 230.0.0.1 is a multicast address defined by RFC 5771 (IPV4) and RFC 4291 (IPV6) and cannot be changed to any other address.

Modifying the UDP Messaging port settings in the editor is preserved in Saved/Config/Windows/Engine.ini:

Saved/Config/Windows/Engine.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[/Script/UdpMessaging.UdpMessagingSettings]
EnableTransport=True
bAutoRepair=True
bStopServiceWhenAppDeactivates=True
UnicastEndpoint=0.0.0.0:0
MulticastEndpoint=230.0.0.1:11111
MessageFormat=CborPlatformEndianness
MulticastTimeToLive=1
EnableTunnel=False
TunnelUnicastEndpoint=
TunnelMulticastEndpoint=

[/Script/Concert.ConcertClientConfig]
bInstallEditorToolbarButton=True

This will not be stored in the project’s Config. If you want this configuration to be included with the project submission, you can add the above configuration to Config/DefaultEngine.ini (the same applies to Enable Multi-user Toolbar Button).

After modification, start UnrealMultiUserServer to use the changed port:

Network Strategy

Multi-User Editing primarily targets users on the same LAN or VPN network. However, there are some distinctions concerning different types of networks within the same LAN.

Same Subnet of LAN

If the server and clients are all on the same subnet, for instance, the server is at 192.168.2.123 and clients at 192.168.2.X, in this case, you only need to set the UnicastEndpoint to 0.0.0.0:0 or 192.168.2.X:0, while keeping the MulticastEndpoint as 230.0.0.1:11111. This setup allows clients to successfully locate the server, as previously described.

Different Subnets of LAN

In situations where the server and some clients are on the same subnet, but others are not, it becomes more complex. For example:
Server: 192.168.2.123
Client A: 192.168.2.124
Client B: 192.168.3.125

In this case, if you use the previous configuration intended for the same subnet, it will prevent Client B from finding the server. Thus, you need to set UnicastEndpoint separately.

First, the server cannot set UnicastEndpoint to 0.0.0.0:0 upon startup; instead, it needs to specify the current Server’s IP and link port, such as:

1
Engine/Binaries/Win64/UnrealMultiUserServer.exe -UDPMESSAGING_TRANSPORT_UNICAST=192.168.2.123:11112 -UDPMESSAGING_TRANSPORT_MULTICAST=230.0.0.1:11111

Clients then need to set the server’s Static EndPoints in the UE editor under Project Settings-Plugins-UDP Messaging:

The value for Static EndPoints should take the form ServerIP:UNICAST_PORT, such as the server’s startup configuration of 192.168.2.123:11112.

By employing this configuration, different subnets under the same LAN can successfully locate the started server (though keep in mind to add the UNICAST/MULTICAST ports in the firewall allowance).

Firewall Strategy

Be aware that since Multi-User Editing utilizes the UDP protocol, the specified ports must be allowed through the firewall to detect the server.

Windows users can employ the following batch file to add firewall rules, saving it as .bat and executing it with administrative privileges:

1
2
3
4
netsh advfirewall firewall add rule name="allowMultiUserServer" protocol=TCP dir=out localport=11111,11112 action=allow
netsh advfirewall firewall add rule name="allowMultiUserServer" protocol=TCP dir=in localport=11111,11112 action=allow
netsh advfirewall firewall add rule name="allowMultiUserServer" protocol=UDP dir=out localport=11111,11112 action=allow
netsh advfirewall firewall add rule name="allowMultiUserServer" protocol=UDP dir=in localport=11111,11112 action=allow

Mac and Linux users can utilize ufw for firewall configuration:

1
2
$ ufw allow 11111/udp
$ ufw allow 11111/tcp

Independent Server Process

The previous section discussed starting a server via the Multi-User Browser in the UE editor. However, the server does not necessarily require the editor to be launched. UE can also start the server by launching a new process with command line parameters, allowing for manual command line initiation of the Multi-User Server:

1
Engine/Binaries/Win64/UnrealMultiUserServer.exe -UDPMESSAGING_TRANSPORT_UNICAST=0.0.0.0:0 -UDPMESSAGING_TRANSPORT_MULTICAST=230.0.0.1:11111

The server’s configuration can be specified through command line parameters or configuration files. The configuration file for the standalone server process can be found at:

Engine/Programs/UnrealMultiUserServer/Saved/Config/WindowsNoEditor/Engine.ini
1
2
3
4
5
6
7
8
[/Script/UdpMessaging.UdpMessagingSettings]
EnableTransport=True
UnicastEndpoint=0.0.0.0:0
MulticastEndpoint=230.0.0.1:11111
MulticastTimeToLive=1
EnableTunnel=False
TunnelUnicastEndpoint=
TunnelMulticastEndpoint=

This is equivalent to specifying through the command line.

Independent Server Program

Since UE’s Multi-User Server launches a separate UnrealMultiUserServer process, we need to clone and download the entire engine to run the Multi-User Server program. This can be wasteful for our requirements, as we only need the independent server program with no need for complete engine functionality. Thus, we can find a way to extract it.

UnrealMultiUserServer is a Programs type program in the engine. I previously wrote articles about related content: Create A Standalone Application in UE4. It essentially uses UE’s codebase and plugins as an independent program, akin to UE4Editor, but by default, its LinkType is Modular, meaning that all modules referenced in the code are contained in separate DLLs. This aligns with UE editor’s design model.

Thus, by default, the UnrealMultiUserServer program is only a few dozen KB. The actual functionality is implemented via dynamically linked libraries; we need to modify the compilation mode to compile all the engine modules it requires into a single executable by changing UnrealMultiUserServer.target.cs:

1
2
3
4
// from
LinkType = TargetLinkType.Modular;
// to
LinkType = TargetLinkType.Monolithic;

After changing to Monolithic and executing the compilation, UBT will link all the Program’s referenced modules into a single executable program. This part is discussed in more detail in another article of mine: UE Build System:Target and Module.

This operation can only resolve references to internal engine modules. The UnrealMultiUserServer program still references other plugins, so Program plugin support must be enabled in target.cs:

1
2
bCompileWithPluginSupport = true;
bBuildDeveloperTools = true;

To see which specific plugins it depends on, you can view the RuntimeDependencies section within UnrealMultiUserServer.target:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"RuntimeDependencies": [
{
"Path": "$(EngineDir)/Plugins/Messaging/UdpMessaging/UdpMessaging.uplugin",
"Type": "UFS"
},
{
"Path": "$(EngineDir)/Plugins/Developer/Concert/ConcertSync/ConcertSyncServer/ConcertSyncServer.uplugin",
"Type": "UFS"
},
{
"Path": "$(EngineDir)/Plugins/Developer/Concert/ConcertMain/ConcertMain.uplugin",
"Type": "UFS"
},
{
"Path": "$(EngineDir)/Plugins/Developer/Concert/ConcertSync/ConcertSyncCore/ConcertSyncCore.uplugin",
"Type": "UFS"
},
{
"Path": "$(EngineDir)/Plugins/Runtime/Database/SQLiteCore/SQLiteCore.uplugin",
"Type": "UFS"
}
]

This indicates that the UnrealMultiUserServer references these several plugins, and we need to place the directories of these plugins from the engine into the corresponding folder of the standalone program while maintaining the relative paths as in the engine.

Still, this isn’t sufficient; we need to add the plugins to the enable list to ensure the program loads them at startup, avoiding module loading errors:

1
2
3
4
5
6
7
8
9
10
LogPaths: Warning: No paths for game localization data were specifed in the game configuration.
LogInit: Warning: No paths for engine localization data were specifed in the engine configuration.
LogInit: WinSock: version 1.1 (2.2), MaxSocks=32767, MaxUdp=65467
LogUdpMessaging: Initializing bridge on interface 0.0.0.0:0 to multicast group 230.0.0.1:6666.
LogSyncServer: Error: ConcertSyncServer Module is needed for proper execution. Initialization failed!
LogSyncServer: Error: ConcertSyncServer Module is needed for proper execution. Initialization failed!
LogSyncServer: Display: Multi-User Editing Server Shutdown
LogSyncServer: Display: Multi-User Editing Server Shutdown
LogExit: Preparing to exit.
LogExit: Object subsystem successfully closed.

The solution is to add the EnablePlugins list in target.cs:

1
2
3
4
5
EnablePlugins.AddRange(new string[]
{
"UdpMessaging",
"ConcertSyncServer"
});

With this adjustment, the standalone program we extracted will load the two required plugins at startup. Lastly, we also need to extract the original Internationalization and Localization folders from Engine/Content.

We don’t require code or debug symbols; hence we can remove excess files:

1
2
3
4
find . -name "Source"|xargs rm -rf
find . -name "Intermediate"|xargs rm -rf
find . -name "*.pdb"|xargs rm -rf
find . -name "*.modules"|xargs rm -rf

The final directory structure of the standalone UnrealMultiUserServer program would be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
+---Binaries
| \---Win64
| UnrealMultiUserServer.exe
+---Content
| +---Internationalization
| +---Localization
|
\---Plugins
+---ConcertMain
| | ConcertMain.uplugin
| |
| \---Binaries
| \---Win64
| UE4Editor-Concert.dll
| UE4Editor-ConcertTransport.dll
| UnrealMultiUserServer-Concert.dll
| UnrealMultiUserServer-ConcertTransport.dll
|
+---ConcertSyncCore
| | ConcertSyncCore.uplugin
| |
| +---Binaries
| | \---Win64
| | UE4Editor-ConcertSyncCore.dll
| | UnrealMultiUserServer-ConcertSyncCore.dll
| |
| \---Config
| BaseConcertSyncCore.ini
|
+---ConcertSyncServer
| | ConcertSyncServer.uplugin
| |
| \---Binaries
| \---Win64
| UE4Editor-ConcertSyncServer.dll
| UnrealMultiUserServer-ConcertSyncServer.dll
|
+---SQLiteCore
| | SQLiteCore.uplugin
| |
| \---Binaries
| \---Win64
| UE4Editor-SQLiteCore.dll
| UnrealMultiUserServer-SQLiteCore.dll
|
\---UdpMessaging
| UdpMessaging.uplugin
|
+---Binaries
| \---Win64
| UE4Editor-UdpMessaging.dll
| UnrealFrontend-UdpMessaging.dll
| UnrealLightmass-UdpMessaging.dll
| UnrealMultiUserServer-UdpMessaging.dll
|
\---Resources
Icon128.webp

Execution effects:

1
2
3
4
5
6
7
8
C:\Users\lipengzha\Desktop\UnrealMultiUserServer\Engine\Binaries\Win64>UnrealMultiUserServer.exe
LogPaths: Warning: No paths for game localization data were specifed in the game configuration.
LogInit: Warning: No paths for engine localization data were specifed in the engine configuration.
LogInit: WinSock: version 1.1 (2.2), MaxSocks=32767, MaxUdp=65467
LogUdpMessaging: Initializing bridge on interface 0.0.0.0:0 to multicast group 230.0.0.1:6666.
LogTemp: IConcertSyncServerModule::Get().ParseServerSettings
LogSyncServer: Display: Multi-User Editing Server Initialized (Name: lipengzha-PC0, Version: 4.25, Role: MultiUser)
LogSyncServer: Display: Multi-User Editing Server Initialized (Name: lipengzha-PC0, Version: 4.25, Role: MultiUser)

Session Configuration Storage

When the Multi-User Server is started, all sessions created by users will be stored on the server side by default in the following path:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
C:\Users\lipengzha\Desktop\UnrealMultiUserServer\Engine\Programs>tree /a /f
\---UnrealMultiUserServer
+---Intermediate
| \---MultiUser
| \---35E93D4D493990231B6D30B582298091
| Session.db
| Session.db-wal
| SessionInfo.json
|
\---Saved
+---Logs
| UnrealMultiUserServer.log
|
\---MultiUser
Repositories.json

The next time the server is started, these sessions will automatically be created, avoiding the need to recreate them.

Conclusion

This article recorded the startup and configuration process of multi-user editing in UE, and extracted an independent Multi-User Server program without requiring the complete engine content, thereby facilitating the deployment of multi-user editing services. Future work will include a detailed analysis of the internal implementation mechanisms and synchronization strategies.

References

The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:UE多用户协同编辑服务部署指南
Author:LIPENGZHA
Publish Date:2021/08/05 16:15
World Count:8.9k Words
Link:https://en.imzlp.com/posts/25226/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!