New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Teleport-aware client-side terrain loading #14367
Comments
Good, well written issue. I have thought about this problem as well and thought the alternatives you've listed should be enough from the mod side but I never cared enough to actually try it out. But now you've convinced me without engine support such a feature is only ever going to be half-complete due to rendering. Portals, teleportation pads, and the like are common in Minetest so having the destination(s) be pre-loaded is a good thing. |
Continued loading from multiple positions is actually quite expensive. (Just look at RemoteClient::getNextBlocks(...)) |
I don't imagine this is going to change the amount of work that Minetest needs to do, it is just going to spread out the existing workload between multiple different locations. It is of course always a modder's responsibility to ensure they're using the tools they're given appropriately, and there are a lot of responsible people out there who push the boundaries of what our engine can do and we should encourage them. The idea that if we have an "add loading position" API, we'd also have a "delete loading position" and "get all loading positions" API seems obvious to me, but maybe it's worth being explicit about that. If loading positions have properties other than their identity itself, we'd probably also want an "update" API, unless removal/re-adding can be done without generating extra network noise that an update API wouldn't have to. If we allow multiple loading spots, we should allow having a "metric" for them that gets added to the block distance. For example, if your draw distance is 10 blocks, and you are 3 blocks away from a teleporter, you should be able to add the loading spot for the teleporter destination with a metric of 3, which tells the engine to prioritize loading a block that's 5 blocks away from that new loading spot as if it were 8 blocks away. That way we can still keep the blocks that are already close to the player loading with higher priority. The metric doesn't just have to be physical distance to the teleportation source, but modders can use heuristics for the metric computation, e.g. distance squared instead of distance, to account for the probability that the player may not enter the teleporter at all. |
Problem
There are situations where the player may be about to suddenly move somewhere very far away, such as a teleportation, or an attached spectator moving to a different camera position.
In many cases, the game/mods may have ways of knowing that this is going to happen (a planned/timed/scripted camera move, or a player is very close to a teleportation pad with a known destination).
Normally, we load terrain that is near the player, and then load terrain surrounding that, so that as the player moves around, their experience of the world is as seamless as possible: assuming the performance of the system can keep up as intended, they should never see unloaded terrain other than at the very fringes of their fog/horizon after the initial connection. Teleports break this, and may put a player in a situation where the terrain arbitrarily close to them is not loaded.
One of the problems this creates is breaking the immersion of a seamless teleport, e.g. where you exactly duplicate the terrain at the destination to hide the transition (recently added player:add_pos(v) has made these otherwise possible). Another problem is that it can disrupt movement, because players may briefly collide with ignores.
Solutions
The solution proposed by c55 was to have multiple "loading positions".
Right now, there is only one "loading position", which is the location of the player, and that position is used to determine how mapblocks are prepared (loaded, activated, send to clients, mesh-generated). Instead, we should allow multiple such loading positions, and mapblocks will be prepared based on their distance to the closest such position (possibly with some prioritization).
Alternatives
The engine offers a number of components of the solution, but they have a number of limitations:
If a well-timed emerge/forceload and then send_mapblock is executed, and then the player enters the teleport shortly after, then the mapblock can be ready client-side for physics (so players don't collide with ignores) but it's still not ready to display until mesh generation is done (even having a potentially stale mesh would be preferable to no mesh at all). If the timing is NOT good (the player approaches the teleporter, causing the preload, but then pauses for a long time before entering) then the terrain may have unloaded already (defeating the measure) or the terrain has to keep being sent (which can cause significant problems in other areas).
Also, apparently functions like emerge_area and send_mapblock do not reset the TTL if the block was already loaded, so cannot prevent blocks from unloading, so affected blocks keep getting evicted and then reloaded (expensive).
If a set of primitives can be provided that allows me to inform a client to mesh-gen a mapblock it's already received, and I can instruct the various engine stages (server-side loading, client-side loading, client-side mesh) to refresh its TTL on a loaded block so it doesn't get evicted until my mod stops refreshing the TTL (or explicitly advises it to discard) then I wouldn't mind managing this myself (though that wouldn't necessarily be the most optimal interface for all modders).
Additional context
This is a continuation of the underlying objective of #14023, i.e. making "seamless teleports" possible. See that issue for additional context: there are a handful of games that are held back from major improvements or new features by the fact that teleportation jank disrupts gameplay and immersion.
The text was updated successfully, but these errors were encountered: