ue4plugins / LoadingScreen

A plugin for Unreal Engine 4 to expose simple controls for managing load screens.
MIT License
504 stars 163 forks source link

4.22 Slate Widget Workaround #50

Closed alanedwardes closed 5 years ago

alanedwardes commented 5 years ago

This is a horrible workaround that I had to implement for my game to fix a slate loading screen under 4.22. I do not use this plugin directly, but I did use the code from this as a basis for my own module and my version also broke under 4.22.

Hopefully it will allow someone else to raise a PR to "fix" the plugin under 4.22.0 (though the engine change seems completely broken and may well be revised in 4.22.1).

Here's the commit that broke this plugin: https://github.com/EpicGames/UnrealEngine/commit/d0754855294a6d27804a17a334bb13f037854780

The change means that an ActiveMovieStreamer is required for the Slate Widget to ever get initialised, and also for at least one path in the MoviePaths array.

This is a dummy streamer class (doesn't matter where this is defined):

class FNullMovieStreamer: public IMovieStreamer
{
public:
    FNullMovieStreamer()
    {
        MovieViewport = MakeShareable(new FMovieViewport());
    };
    virtual ~FNullMovieStreamer() {};

    virtual bool Init(const TArray<FString>& MoviePaths, TEnumAsByte<EMoviePlaybackType> inPlaybackType) override { return true; };
    virtual void ForceCompletion() override { };
    virtual bool Tick(float DeltaTime) override { return false; };
    virtual TSharedPtr<class ISlateViewport> GetViewportInterface() override { return MovieViewport; };
    virtual float GetAspectRatio() const override { return 0.f; };
    virtual void Cleanup() override { };

    virtual FString GetMovieName() override { return FString(); };
    virtual bool IsLastMovieInPlaylist() override { return false; };

    FOnCurrentMovieClipFinished OnCurrentMovieClipFinishedDelegate;
    virtual FOnCurrentMovieClipFinished& OnCurrentMovieClipFinished() override { return OnCurrentMovieClipFinishedDelegate; }

private:
    TSharedPtr<FMovieViewport> MovieViewport;
};

This should be referenced as a private member in FLoadingScreenModule: https://github.com/ue4plugins/LoadingScreen/blob/master/Source/LoadingScreen/Private/LoadingScreenModule.cpp#L10-L27

private:
    TSharedPtr<class FNullMovieStreamer> NullMovieStreamer;

Register this with the MoviePlayer at module startup https://github.com/ue4plugins/LoadingScreen/blob/master/Source/LoadingScreen/Private/LoadingScreenModule.cpp#L53

    NullMovieStreamer = MakeShareable(new FNullMovieStreamer());
    GetMoviePlayer()->RegisterMovieStreamer(NullMovieStreamer);

Ensure that there is at least one movie path specified, this can probably be done from the plugin configuration UI, but can also make sure it happens by adding an empty string into the MoviePaths array here: https://github.com/ue4plugins/LoadingScreen/blob/master/Source/LoadingScreen/Private/LoadingScreenModule.cpp#L83

This should fix the Slate based loading screen.

alanedwardes commented 5 years ago

Just to be more specific with why this works - the PlayMovie code now checks whether there is an active movie streamer here before initialising a Slate widget: https://github.com/EpicGames/UnrealEngine/blob/d0754855294a6d27804a17a334bb13f037854780/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp#L370

That can only be set by loop: https://github.com/EpicGames/UnrealEngine/blob/d0754855294a6d27804a17a334bb13f037854780/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp#L360

Which is also gated by this method: https://github.com/EpicGames/UnrealEngine/blob/d0754855294a6d27804a17a334bb13f037854780/Engine/Source/Runtime/MoviePlayer/Private/DefaultGameMoviePlayer.cpp#L702 (which checks whether there is more than 0 paths and more than 0 registered streamers).

deathlyrage commented 5 years ago

Thanks fixes worked for me.

gaslightgames commented 5 years ago

More thanks over here - this fixed the problem for me, too.

I did also have to add the module "RHI" to the Plugins Build.cs Public Dependency, as I was getting unresolved externals, one of which was "FRHIResource::Bypass" and a quick search showed it was in the RHI module.

ScorpiusGames commented 5 years ago

Great fix, it works!

infinstarlight commented 5 years ago

Is there an expected error in Visual Studio? In my StartUpModule function in LoadingScreenModule.cpp I have this error

Error (active) E0312 no suitable user-defined conversion from "TSharedPtr<FNullMovieStreamer, ESPMode::NotThreadSafe>" to "TSharedPtr<IMovieStreamer, ESPMode::NotThreadSafe>" exists HellsAsylum W:\UnrealProjects\HellsAsylum\Plugins\LoadingScreen-master\Source\LoadingScreen\Private\LoadingScreenModule.cpp 56

I was able to compile the game just fine and running my game in a standalone process showed the loading screen before starting the game, as intended, but I'm a little worried by this.

alanedwardes commented 5 years ago

Hi all,

A fix is now available in 4.22.1 to address these issues: https://forums.unrealengine.com/unreal-engine/announcements-and-releases/1612034-4-22-1-hotfix-released

The issue on the Epic side is UE-73037. Upgrading to 4.22.1 should resolve this issue and make this workaround no longer necessary.

Alan

ScorpiusGames commented 5 years ago

Great news, thanks!

lucastucious commented 5 years ago

Doesn't resolve the problem for me...