I’ll be honest in most of my years experience, loading screens aren’t trivial in general. Getting them to animate or play a movie is always critical for console platform cert requirements (basic UX as well), but changing threads so you can do the animation while the thread loads new content isn’t always straightforward. Managing the render context, etc. Our render guys make that magic happen.
In UE3 we would pre load Bink movies and play them on another thread while work was done. Again left the heavy lifting to a third party.
Point being, getting actual progress bars on top of that can be quite a pain, so many games just stick to “animating spinny thing” to fulfill the requirements. Accurate progress bars require foreknowledge of literally everything you are about to load. At the lowest level, as you read content byte by byte you need to pass that information up to the high level so you can show a percentage loaded.
Once upon a time, at a previous job, during the build disc pass we would scan all the content for each level and generate a manifest with each file and its size as a lookup. Then as we loaded we would relay this information up (seek/tell on CD/DVD was slow). But as games these days aren’t necessarily “load level X” because of memory, open world, streaming, you name it, a prepass may not be possible.
I guess the point is trying to get a loading bar that’s accurate isn’t always worth it.
As for showing a loading screen, I would argue there is also no one size fits all approach to this. Trying to detect “loading now” is probably too late to show the loading screen. And “done loading” is too early to remove it. Inevitably you’re going to have game elements that disappear pre travel/load because you have to clean it up, or elements that stop ticking/pause as loading starts. It just looks wrong. When you get to the other side, maybe you are the first client to connect and you’re waiting for other players. So now BeginMatch hasn’t been called, and you don’t have enough information to spawn a camera in the right location (waiting on some replication). So you’re looking at no character, with a camera pointing at a rock in the ground. Or you need 5 seconds to do a quick AI nav path pass on all actors in the level. Who knows, it’s up to the game. To avoid bad presentation you wait for N other things to occur before you reveal the level.
Every Epic game I’ve worked on manually called ShowLoadingScreen() and manually removed it when ready. Maybe in InitGame() at the destination AGameMode you say SetTimer(CheckForLoadingScreenRemoval, .5) and every half second you look around and determine if its a good time to remove it, then stop the timer. That way its not a wasteful check in your Tick() loop.
I’ll try to stop by later and talk about seamless vs nonseamless (hard) travel. For now though, you always have to do a hard travel to get on the server. It’s a blocking load, just the way LoadMap works. Seamless travel is for transition from lobby to game or map cycle. You have your network connection, tick the engine, replicate actors, and can migrate actors from one level to another if you want.