Players & movement
Travel
Move the local player's body and know when it has really arrived: the two teleports and why there are two, what βsettledβ actually tests, raw settle tickets, noclip and the map pick.
On this page5 sections
Move players with the server-owned travel APIs. Use teleportation and placement operations that coordinate client streaming instead of writing transforms directly.
Everything on Open77.travel is client-side and requires the player.travel permission.
That permission belongs only in operator-audited resources: the native lab commands these
replace are refused while a multiplayer session is active, so an ACL-checked server
command asking a trusted client resource to call them is the intended path.
If the server is the one deciding where somebody goes, do not reach for this page β
use Open77.players.teleport, which drives exactly the
machinery described below and answers the server with the result.
The two teleports, and why there are two
Open77.travel.teleport(x, y, z, heading) -- fire and forget
Open77.travel.teleportAndSettle({ x = x, y = y, z = z }, heading) -- Promise
Open77.travel.teleport queues one engine request and returns. It checks a finite
transform and a live player, and that is all it knows. In particular it knows nothing
about streaming, and that gap is not academic:
- The engine executes the teleport on a later tick, so a position sampled in the frame that asked for it is the old one.
- If the floor at the destination has not streamed in yet, the body falls through it.
- Cyberpunk's own
Failsafe/PlayerTeleportationIfFallsUnderWorldthen returns the player to the last place the engine considers safe β the save's spawn of record, which can be kilometres away β and nothing tells the caller.
Use the travel APIs' streaming and settle checks for distant destinations. Repeating a raw transform write does not make an unloaded destination safe.
Open77.travel.teleportAndSettle is the same teleport with the answer attached.
CreateThread(function()
local arrival, reason = Open77.travel.teleportAndSettle(
{ x = 1669.75, y = -739.12, z = 49.86 }, 180):await()
if not arrival then
print("did not arrive: " .. tostring(reason))
return
end
print(("%s after %d attempts, %d pins, %d ms")
:format(arrival.state, arrival.attempts, arrival.pins, arrival.elapsedMs))
end)
It resolves with { state, x, y, z, attempts, pins, elapsedMs }:
state |
What it means |
|---|---|
settled |
The body was on the point, grounded, and in no fall state for three consecutive frames. This is the answer. |
near |
The 1.5 s window closed with the body on the point but never reported grounded β a mark on a prop, or a very slow stream-in. An honest success with a weaker claim. |
and rejects with a stable reason:
| Reason | Meaning |
|---|---|
settle_timeout |
The body never stood at the destination inside the budget (default 12 s, options.timeoutMs is 1000..30000). |
settle_superseded |
Another teleportAndSettle started before this one finished. There is one body, so there is one session. |
settle_cancelled |
Open77.travel.cancelSettle stopped the watch. The body stays wherever it currently is. |
player_unavailable, teleport_unavailable, invalid_transform |
The teleport itself was refused; the watch never started. |
What "settled" is actually testing
There is no streaming query anywhere in the engine surface Open77 can reach.
StreamingSector, worldStreaming, IsStreamed, RequestStreaming, StreamingWorld and
worldRuntimeScene were all swept for; none of them is callable. So "is the destination
streamed?" is not a question that can be asked, and the API deliberately does not pretend
otherwise.
What can be observed is the body, and that turns out to be the question a caller really has: can I let go of this yet? The watch asserts three things together, every frame:
- on the point β within 4 m horizontally and 6 m vertically of the mark;
- grounded β the player state machine says so;
- not falling β the fall state is
None. Not "not a lethal fall": the second production trace readfall=Safewhile the body sank through an unloaded floor.
All three, for three consecutive frames. A single near sample proves nothing; the trap
showed the body at the wrong point twice before reading grounded=yes.
When the body is on the point but sinking β not grounded, and more than 0.75 m below the
mark β the teleport is re-issued every 250 ms for up to 7 s. That resets the fall
before the failsafe can fire and keeps the engine's streaming prefetch aimed at the mark,
until the floor arrives. pins in the result counts how many times that happened; a
non-zero pins means the destination was not resident when you asked for it.
If the body ends up somewhere else entirely when the window closes, the whole placement is re-issued, up to the session's timeout.
The same watch drives the respawn placement in LifeReplication β one implementation, one
set of constants, both paid for by the same two incidents.
Raw settle tickets
teleportAndSettle is a thin wrapper over three natives, which are there for a caller who
wants to drive the poll itself:
local ticket, reason = Open77.travel.beginSettle(x, y, z, heading, timeoutMs)
local status = Open77.travel.settleStatus(ticket) -- state, reason, x, y, z, attempts, pins, elapsedMs
Open77.travel.cancelSettle(ticket)
settleStatus returns nil, unknown_settle_ticket for a ticket that is neither the live
session nor the last one to finish.
Noclip and the map pick
Open77.travel.setNoclip(enabled)
Open77.travel.isNoclip()
Open77.travel.setNoclipSpeed(metresPerSecond) -- 0.1 .. 500
Open77.travel.getNoclipSpeed() -- current base speed, including wheel changes
Open77.travel.setMapPick(enabled)
Open77.travel.isMapPick()
Noclip moves through the same teleport facility and never takes ownership of the player's movement component. It is camera-relative, uses the player's configured forward/back/left/right keys, and submits one bounded movement request per running game frame. Releasing a movement key does not leave a target that continues to converge.
- Space / Ctrl: ascend / descend; mouse wheel: adjust base speed (20% per notch).
- Shift: 4x boost; Alt: 0.25x precision; both can be combined.
- XInput: left stick moves, right stick looks, triggers ascend/descend, LB boosts and RB slows.
- Diagonal movement is normalized. Menus, focused WebUIs, the developer console and loss of window focus suspend movement input; the held position is retained.
- Native movement/combat restrictions belong to noclip and are released on exit. It does not heal the player, pause world time or clear restrictions belonging to other resources.
- Activation requires a living, attached player outside vehicles and workspot animations.
setNoclipreturnsfalse, reasonif refused. Death, body replacement or entering a vehicle stops flight. Stopping the owning resource releases flight on the next running frame. - Only the resource which enabled noclip can disable it. All travel calls still require
player.travel; a gamemode must also enforce server-side ACL before delegating admin use.
The admin package retains /admin.self.noclip, /admin.self.fly and /admin.self.speed.
Its compact HUD shows current speed and controls without capturing input. Native wheel
changes are reflected in both admin interfaces. The diagnostic noclip.state is read-only
and reports the controller, owning resource, paused input and safety guards.
setMapPick only lets the world map publish a double-clicked point;
it moves nobody, and it does not bypass the ACL-checked server command that consumes the
point.
Loading-screen integration
A long-distance teleport may open Cyberpunk's native loading screen. Use the loading-screen lifecycle to display your own cover or hide a HUD. Loading completion is presentation information; keep the travel API's settling checks for destination readiness.
// For agents & LLMsthis page as Markdownllms.txtllms-full.txt
