The Teleportation Manifesto

Back


The Goal

We will explain the following process in Fractal Block World: teleporting the player from chunk A to chunk B, and then back again if there is a problem.

That catch is that when we start at chunk A, the chunk B may not be in the active chunk tree yet. Similarly, when we are at chunk B, the chunk A may no longer be in the active chunk tree. This is where the complication arises.

Step 1: Get Destination Path

The player is in chunk A. Somehow get the block path and lbp (local block position) of the chunk B we want to teleport to.

We can even work with an "offset" into the target chunk B rather than an lbp.

Note that chunk B need not exist in the active chunk tree at this time.

Step 2: Make the Engine Do Teleportation

Call the following functions:
  1. ga_move_set_body_spirit()
  2. ga_explore_while(lua_func, lua_win)
  3. ga_tele(block_path, offset)
Note: these must be called within the SAME frame.

Changing our body mode to "spirit" will make us not collide with the world. It also makes us not render the WORLD. It also makes teleportation faster because we do not explore as much. The basic reason why it is so fast is because the following: If the chunk_id of the player is different from what it was last frame, then the engine effectively sets the level radius of each level to 0. The player needs to be at a chunk for at least two frames in order for the engine to create chunks AROUND the viewer's chunk. So, spirit mode is ideal for "drilling down" into the chunk tree.

For the ga_explore_while function call, we pass the (string) name of a Lua function that functions as a "while loop". That is, the function is called over and over again until it returns false. However, this might not have the purpose that you might expect, which we will explain later. You can also optionally pass to the ga_explore_while function the (string) name of a Lua window which is rendered and gets input every frame until the while loop function returns false.

The ga_tele function call actually causes the teleportation to happen, which we explain in the next step.

Step 3: Wait Until the Engine Finishes Teleportation

Wait.

Because you called ga_tele, the engine will gradually modify the chunk tree to move the player to the target block path (moving the player to chunk B). While this is happening, the engine renders a loading screen and does not actually call any Lua function of the package. This may take a few seconds.


Step 4: Note That Now Your While Loop Function Is Being Called

The engine will finish the teleportation and will begin to call Lua code again. The player is now "in chunk B", but they are in spirit mode, so they do not really have a body exactly.

Because you had called the ga_explore_while function, instead of calling normal game functions, the engine will call the "while loop" function you registered when you called ga_explore_while. It will also call the input and render functions of the (optional) window whose name you passed to the ga_explore_while function.


Step 5: Continue The While Loop Until You Decide If Chunk B Is Safe

At this point, the game will be in the while loop. What is the purpose of this loop? Well, you need to make sure it is safe to teleport to chunk B. What if it is completely filled with solid blocks? What if you wanted to teleport to a waypoint, but somehow there are no waypoints in chunk B?

You want to query chunk B to see if it is suitable. You might think you can just do this check in a single frame.

Maybe you can. However if the player's normal body size is more than one block tall, there is an issue that the player's destination would have them be partially in chunk B but also partially spill over into an adjacent chunk.

Since we are still in spirit mode, there might not be any adjacent chunks to the player's chunk that are loaded! We must wait a few frames for the engine to load nearby chunks for us to assess whether it is really safe to end the teleportation process. Once we have enough information, we need to return false from the while loop function. Just before we do return false, we need to do a few things.

Step 6: If Chunk B Is Safe, Finish

If we calculated that the destination chunk B is OK, we need to do the following:
  1. Call ga_move_set_body_spirit_off(). This will reset the player's body mode and dimensions to what they were just before we called ga_move_set_body_spirit().
  2. We could move the player slightly within the chunk. Theoretically, we could teleport the player to an adjacent chunk (on the same level) with the ga_tele_same_level function. However, it might be best to keep things simple and not do this.
We are now done!

Step 7: If Chunk B Is NOT Safe, Perhaps Teleport Back To Chunk A

Suppose we could not do Step 6 because we calculated that the destination chunk is NOT ok. We are now in trouble!!!

Theoretically you could do whatever you want, like display an error screen to the player that says "bummer dude" and then kill the player and take away all their ammo.

However what you probably want to do is teleport the player back to where they started before the teleportation (chunk A). To do this, first note that the player is still in spirit mode. You want to call the ga_tele function but giving it the path and lbp of where the player started. So, you needed to record this information at the beginning. You could store it in a "global" variable for example.

Next, you MIGHT want to do another ga_explore_while call. Indeed, you could have chosen not to end the old while loop. In this case after the engine teleports you back to your starting position, the engine will continue calling this while loop. However one could argue that doing any sort of while loop for the back teleportation (either part of the original while loop or a second one) is not needed: the teleportation back SHOULD succeed.

Be careful about being in one while loop and then setting up another while loop. The system only has at most one explore while loop. When you call ga_explore_while(lua_func, lua_win) from the inside of one while loop, you must return true from that while loop. Here is an example, in a file which let's say is called test.lua:
function p.while_loop_1()
    if( SOMETHING_INTERESTING_HAPPENS ) then
        local dummy_win = ""
        ga_explore_while("test.while_loop_2", dummy_win)
        --At this point, the engine thinks we are in "while_loop_2".
        return true --Continue "the" while loop (while_loop_2 will be called next).
    else
        --Do stuff...
        return true --Continue the while loop (while_loop_1 will be called again).
    end
end

function p.while_loop_2()
    if( COMMON_CASE ) then
        return true --Continue this while_loop_2 function.
    else
        return false --End the while loop.
    end
end

Step 8: If Teleporting Back To Chunk A Fails, Oh Snap!

If the teleportation BACK to chunk A does not succeed, you need to decide what is the right thing to do.

Perhaps you should teleport the player to their current respawn point.

We are now done!

Note: If you have an explore while loop where the function is called many times, you may consider having the function call ga_render_skip_next_frame to pause rendering. This is done for blue rings, and it speeds up the teleportation by a factor of 3 or so. However, since we are using the ga_tele function, it does not really matter.