So you'd use something like this:
Note that my code doesn't handle the end-of-spectating, that will need even more magic (a global table of who's spectating, g_Spectating[SpectatorName] = SpectatedName) and the end-spectate command writing into that table. Also I didn't test the code at all, it might not even run.
local NUM_TICKS = 5
function HandleSpectateCommand(a_Split, a_Player)
-- Store the player name of the spectator and the spectated player, so that you can access them later on:
local SpectatorName = a_Player:GetName()
local SpectatedName = a_Split[2]
if (SpectatedName == nil) then
-- TODO: handle error
end
local Callback = function(a_World)
-- This is the callback that will be called after NUM_TICKS ticks
-- Note that it CANNOT access a_Player!
-- (because the player could have disconnected in the meantime and the object would be invalid then, making the server crash)
-- Instead, we need to look up both players by name:
a_World:DoWithPlayer(SpectatorName,
function (a_Spectator) -- This function will be called and a_Spectator will be set to the cPlayer object of the spectator, *if* they exist
a_World:DoWithPlayer(SpectatedName,
function (a_Spectated) -- This function will be called and a_Spectated will be set to the cPlayer object of the spectated player, *if* they exist
local pos = a_Spectated:GetPosition()
pos.y = pos.y + 2
a_Spectator:TeleportToCoords(pos.x, pos.y, pos.z)
a_World:ScheduleTask(NUM_TICKS, Callback) -- re-schedule for after another 5 ticks
end
) -- DoWithPlayer(SpectatedName)
end
) -- DoWithPlayer(SpectatorName)
end
-- Schedule the callback to be called after NUM_TICKS ticks:
a_World:ScheduleTask(NUM_TICKS, Callback)
end
Note that my code doesn't handle the end-of-spectating, that will need even more magic (a global table of who's spectating, g_Spectating[SpectatorName] = SpectatedName) and the end-spectate command writing into that table. Also I didn't test the code at all, it might not even run.

