We’re working on trying to make a custom online subsystem work with PIE. UE4 has basic support for this, primarily through Online::GetSubsystem which takes a world pointer; with UE_EDITOR compiled in this generates a world specific identifier. The idea is that the factory then creates a new online subsystem which is used for that PIE session.
While this setup exists in theory, in practise it doesn’t work. All existing subsystems, aside from the Null one, have an internal singleton. If a subsystem tries to get created again via CreateSubsystem an error is logged and nothing is created. For some subsystems this is the right thing to do (for example Steam only functions as a singleton) but for our system, and others that can support multiple contexts, having more than one active would work just fine.
By creating a new subsystem that does allow multiple allocation it quite quickly becomes noticable that this hasn’t been a feature that has been used. There are still a fair few places in UE that call IOnlineSubsystem::Get() which would return the global, not world specific one. For a large extend this is fixable by changing the call and passing in GetWorld() if ::Get is currently called from an UObject derived class (for example in UGameInstance::Init).
The question comes down to if there is an architectural desire to actually make online subsystems properly work for PIE. The commonly used IOnlineSubsystem::Get() that doesn’t take any parameters should not be allowed anymore to avoid calling mistakes and interfaces allocated from an online subsystem (that get passed the owning subsystem) should use the owningSubsystem pointer rather than a global Get, to ensure that the correct system instance is called. Since modifying this involves quite a few changes to the existing codebase it is not something that is easily supported by us as a 3rd party.
Related, in writing an initial implementation there is a problem with FOnlineSubsystemModule::GetOnlineSubsystem and how it allocates new subsystem instances. This is not something that the current subsystems (aside from Null) run into since they are all effectively singletons and will fail to create more than one subsystem. The issue is that when CreateSubsystem is called for a specific instance name it is not directly added to the FOnlineSubsystemModule::OnlineSubsystems map. Because CreateSubsystem doesn’t only allocate but also calls Init on the newly allocated subsystem, any code that calls Online::GetSubsystem or similar before the call Init completes will result in FOnlineSubsystemModule::GetOnlineSubsystem allocating another instance of the subsystem with the same name. When called from the same thread this is quite noticable as the code recurses until a stack overflow occurs, but in the case of Init registering callbacks to the operating system (or other systems) it is possible for those callbacks to be called and cause an subsystem creation (with the same instance name) from a different thread.
There are a few possible solutions to this. Init could only gets called after the subsystem has been added to the map, but that risks the subsystem being used before it is initialised. An improvement there is to have some kind of flag that gets set on init completion and an error is raised of GetOnlineSubsystem is called for the same instance that already is registered in the map but hasn’t completed initialisation yet. Another option is to have a clear post-init method that callbacks etc have to be registered from.
Either of those solutions require changes to FOnlineSubsystemModule::GetOnlineSubsystem so are likely something that has to be driven by Epic.