Knowledge base

Player control: moving V, the camera, interactions and input

Research in progress: some of this may be wrong. These notes record what XF Studio’s research has worked out so far about how Cyberpunk 2077 and its modding frameworks behave. Most of it comes from reading source code and game resources offline; not all of it has been confirmed in the running game, and claims graded hypothesis are unproven. If you spot a mistake or know more, please open an issue or suggest an edit.

Evidence grades

source
Read in engine/framework/tool source or decompiled data.
resource
Observed in extracted game or mod resources.
wiki
Documented in the Modding Docs, text or image.
runtime
Observed in the running game.
hypothesis
Not yet established.

Maturity: Draft. What the game offers a mod for driving V directly: teleporting and walking her, turning the camera instantly or smoothly, reading and choosing interaction and dialogue choices, the other things a player does (crouch, weapons, consumables, menus), and how input reaches the game and could be synthesised from inside it. Consolidated on 29 September 2026 from the decompiled 2.31 script bundle (redscript-cli 0.5.31, final.redscripts SHA-256 2119046f…ee86), the game's input configuration and executable imports, the address library, the red-dump-json RTTI dump (a8e52990, pre-2.3), RED4ext.SDK (ad727771), Cyber Engine Tweaks (v1.37.1-9), Codeware (clone 1.20.4, installed 1.20.5), Appearance Menu Mod, Input Loader and Native Interactions Framework clones, and installed mods read in place (FreeFly 2.4.0, Immersive Third Person - Best Of Both Worlds 1.3.0, 0-Engine 0.13.0). Nothing on this page has runtime evidence yet except where marked. The command design built on it is the player-control design, whose phase 1 is built in XF Runtime Bridge 0.6 (offline only: player.state, player.teleport, player.look, player.action, player.interact.list, input.probe, and glides and looks as behaviours; bridge README); the session-7 card's group E is its first in-game test; experiments/player-control/probe_offline.py reproduces the import, address-library and RTTI facts. Grades follow the knowledge rules.

Game-script citations are paths inside the decompiled bundle; installed-mod citations are paths inside each mod's folder in the mod manager (mods/<mod name>/).

1. At a glance

CapabilityRouteGrade
Teleport with facingGameInstance.GetTeleportationFacility(game).Teleport(player, pos, EulerAngles(0, 0, yaw))source
Turn V instantlyTeleport in place with a new yaw (her yaw is the first-person camera's)source
Aim the camera at a point over timeTargetingSystem.LookAt(player, AimRequest); BreakLookAtsource
Walkable ground and pathsNavigationSystem.FindPointInSphereOnlyHumanNavmesh, IsNavmeshStreamedInLocation, CalculatePathOnlyHumanNavmeshsource
Walk with the game's own locomotionOnly through movement input; no script sets itsource
What V looks at; what the HUD offersTargetingSystem.GetLookAtObject; the UIInteractions blackboardsource
Choose a dialogue lineOnly through input (scroll, confirm); no script or native call is exposedsource
Crouch, weapons, consumables, menusStatus effect, equipment requests, item actions, UI eventssource
Input from inside the game without focusCDPR's functional-test system (FakeInput*), a virtual XInput pad, or the decoded input bufferexistence source; behaviour hypothesis

2. Moving V

  • Teleport. TeleportationFacility has Teleport(object, position: Vector4, orientation: EulerAngles) and TeleportToNode(object, NodeRef), nothing else source orphans.script:31933-31938. Fast travel calls GetFPPCameraComponent().ResetPitch() and then TeleportToNode source core/systems/fastTravelSystem.script:321-341. Appearance Menu Mod teleports V with EulerAngles.new(0, 0, yaw) and pins her by teleporting her onto her own position source AMM Modules/tools.lua:1782-1786, Modules/util.lua:516-523.
  • Teleport checks nothing. Snap a destination with FindPointInSphereOnlyHumanNavmesh(center, radius, NavGenAgentSize.Human, heightDetail) and require IsNavmeshStreamedInLocation; the game's own GetNearestNavmeshPointBelowOnlyHumanNavmesh walks spheres downwards, and IsOnGround casts 0.2 m down against static geometry source core/systems/navigationSystem.script:8, 18, 24-60.
  • Paths. CalculatePathOnlyHumanNavmesh(start, end, agentSize, findPointTolerance) returns a NavigationPath with path: [Vector4] and CalculateLength() source navigationSystem.script:4, orphans.script:29743-29748; an area-effect device uses it to test reachability source cyberpunk/devices/aoeSystem/aoeArea.script:236.
  • Walking is input. The player state machine (PSM) reads the movement actions (GetActionValue(n"MoveX"), n"MoveY", GetInputHeading(), IsMoveInputConsiderable()) to choose its states; the motion itself is native source cyberpunk/player/psm/defaultTransition.script:587-588, 639, orphans.script:42516-42572. MoveX/MoveY map to the left stick and the WASD buttons resource r6/config/inputContexts.xml:895-896, inputUserMappings.xml.
  • The PSM's own nudge. AdjustTransformWithDurations (position, slide duration, rotation, rotation duration, target and distance radius, gravity, curve, parabolic motion), set as the temporary parameter adjustTransform on the PSM's StateContext, moves or turns V over time; melee lunges, takedown alignment and turning a knocked-down V use it source orphans.script:42776-42798, defaultTransition.script:319-345, locomotionTransitions.script:5112-5121. Only PSM callbacks receive a StateContext; Immersive Third Person turns V's body this way from its wrap of StandEvents.OnTick source ITP r6/scripts/immersive_third_person/tpp_camera_bridge.reds:2030-2057. LocomotionParameters.SetUseCameraHeadingForMovement (through the locomotionParameters temporary parameter) is how that mod makes movement follow the camera source orphans.script:45147-45185; ITP tpp_camera_move360.reds.
  • Noclip. FreeFly applies GameplayRestriction.NoMovement and NoZooming (and optionally NoCombat) to V, then teleports her every frame along the active camera's forward and right vectors, turning her by the teleport's yaw plus the mouse's CameraMouseX source FreeFly bin/x64/plugins/cyber_engine_tweaks/mods/freefly/modules/utils/logic.lua, miscUtils.lua.
  • State to check first. The PSM blackboard (PlayerPuppet.GetPlayerStateMachineBlackboard()) carries Locomotion (gamePSMLocomotionStates: Default, Crouch, Sprint, Jump, Vault, Dodge, Workspot, Slide…), HighLevel (Default, SceneTier1-5, Swimming), SceneTier, Vehicle, Combat, Fall, Landing, Swimming, IsInWorkspot, Takedown, BodyCarrying and more source core/blackboard/blackboardDefinitions.script (PlayerStateMachineDef), orphans.script:6647-6693; 0-Engine reads all of them every frame for its state cache source 0-Engine modules/BlackboardCache2.lua. Also VehicleComponent.IsMountedToVehicle(game, player) source core/components/scriptComponents/vehicleComponent.script:255 and SceneSystemInterface.IsEntityInScene/IsEntityInDialogue source orphans.script:32248-32252.

3. The camera

  • Reading the look direction: CameraSystem.GetActiveCameraForward() (pitch = asin(z)), GetActiveCameraWorldTransform(); V's facing GetWorldYaw() source core/entity/entity.script:48.
  • TargetingSystem.LookAt(instigator, out AimRequest) turns the player's camera in yaw and pitch towards lookAtTarget over duration, with maxDuration, easeIn/easeOut, precision, adjustYaw/adjustPitch, endOnTargetReached, endOnTimeExceeded, endOnCameraInputApplied, cameraInputMagToBreak, cameraMouseInputMagToBreak, processAsInput and body-part tracking fields; BreakLookAt, BreakAimSnap end it source orphans.script:22401-22423, 26044-26088. The scanner's target switch (0.1 s) source core/systems/hud/hudManager.script:640-670, melee source defaultTransition.script:720-755, an item action that makes V look at a thrown knife source cyberpunk/items/combat_gadgets/kurtThrowableKnife.script:295-313 and an effect executor (0.25 s, eased) source cyberpunk/strike/executors/executorLookAt.script call it, the last two from outside the PSM.
  • The first-person camera is the player's camera component (GetFPPCameraComponent(), a gameFPPCameraComponent): ResetPitch(), SceneDisableBlendingToStaticPosition(), the placed-component Get/SetLocalPosition and Get/SetLocalOrientation, and the fields pitchMin, pitchMax, yawMaxLeft, yawMaxRight, headingLocked, sensitivityMultX/Y source orphans.script:16646-16664, 27006-27011; SDK game/FPPCameraComponent.hpp. The current pitch is in an unnamed field. Native Interactions Framework pulls this camera 2 m behind V (SetLocalPosition(0, -2, 0)) and widens its limits for an external view source NIF modules/ui/interactionUI.lua:38-62. Whether a local-orientation write sets pitch or is overwritten each frame is hypothesis.
  • Hidden test natives: PlayerFunctionalTests.SetCameraOrientation and RemoveCollision exist in retail RTTI, parameters stripped (§6) source red-dump-json classes/PlayerFunctionalTests.json.
  • Immersive Third Person activates its own camera component (tppCamera) and sets its local orientation and position every frame from an orbit fed by the player's mouse and stick actions caught in PlayerPuppet.OnAction; it locks the first-person camera's heading while free-looking and resets it (ResetPitch, neutral orientation, origin) when switching back source ITP bin/x64/plugins/cyber_engine_tweaks/mods/immersive_third_person/init.lua:1029-1070, 3890-3920, 4490-4600. Its RED4ext plugin ImmersiveThirdPersonMove360 swaps the native handlers of StateGameScriptInterface.GetActionValue and GetInputHeading, guarded against a table it can't verify, so the PSM reads the movement input it wants source the plugin's log strings. A third-person look is therefore that mod's own state, not the game's.
  • A free camera of one's own: spawn base\entities\cameras\simple_free_camera.ent, FindComponentByName("camera"), Activate(blendTime, false), SetFOV, SetZoom, move the entity with Teleport; Deactivate and GetFPPCameraComponent().Activate() to return. AMM holds V still meanwhile with NoMovement, NoCameraControl, NoZooming, FastForwardCrouchLock, NoCombat, VehicleNoSummoning, NoPhone and NoDriving, and shows her head source AMM Modules/camera.lua, Modules/util.lua:541-561.

4. Interactions and dialogue

  • Everything the HUD offers is on the UIInteractions blackboard (global, auto-created): InteractionChoiceHub (InteractionChoiceHubData { id, flags, active, title, choices }), DialogChoiceHubs ({ choiceHubs: [ListChoiceHubData { id, activityState, flags, isPhoneLockActive, title, choices: [ListChoiceData] }] }), ActiveChoiceHubID, SelectedIndex, LootData, ContactsData, ActiveInteractions, InteractionSkillCheckHub, NameplateOwnerID, VisualizersInfo, LastAttemptedChoice, LookAtTargetVisualizerID, HasScrollableInteraction source core/blackboard/blackboardDefinitions.script:805-838; orphans.script:42008-42026, 54489-54552. The HUD listens to exactly these source cyberpunk/UI/interactions/interactionUIBase.script:30-107.
  • A world choice (InteractionChoiceData) carries the inputAction that selects it (Choice1…Choice4 or a hold), isHoldAction, a LocKey localizedName (shown with GetLocalizedText), a type, caption parts and data variants source orphans.script:54537-54552, cyberpunk/UI/interactions/interactionsUIChoiceItem.script:64, 152. A dialogue line (ListChoiceData) carries its text, type, caption parts and inputActionName, its dedicated input where it has one source cyberpunk/UI/interactions/dialogUI.script:312-324.
  • LastAttemptedChoice (InteractionAttemptedChoice { visualizerType, choice, choiceIdx, isSuccess }) records the last choice made and whether it succeeded; the prevention system listens to it source orphans.script:33653-33662, core/systems/preventionSystem.script:1150.
  • Selection is native and input-driven. The interaction manager turns the choice's action into an InteractionChoiceEvent { hotspot, activator, layerData, choice: InteractionChoice { caption, captionParts, data, choiceMetaData }, actionType } on the hotspot's entity source orphans.script:18261-18268, 22133-22144, 35785-35790. The script API of InteractionManager has only IsInteractionLookAtTarget, SetBlockAllInteractions and AreSceneInteractionsBlocked source orphans.script:33671-33678, and SceneSystemInterface has no choice function source orphans.script:32199-32252. Selecting a dialogue line therefore means input: ChoiceScrollUp/Down until SelectedIndex matches, then DialogConfirm (IK_F, IK_Enter, pad X) or the line's own input resource r6/config/inputUserMappings.xml:1175-1200.
  • Devices handle the event with OnInteractionUsed(evt) → ExecuteAction(evt.choice, evt.activator, evt.layerData.tag) source cyberpunk/devices/core/interactiveDevice.script:276-278; containers, mountable vehicles and puppets and the inventory component have their own handlers source core/components/lootContainers.script:113, gameVehicleMountableComponent.script:4-12, inventoryComponent.script:44. Queuing such an event from script, without input, is hypothesis.
  • Usable spots added by Native Interactions Framework are scene interactions (it registers scene resources), so they select like dialogue source NIF r6/scripts/nativeInteractions.reds.
  • A mod can add its own hub to the dialogue widget and let the player choose from it with the usual keys; the answer comes back to the mod, not as input it must synthesise (NPC direction §5) source.

5. Other player actions

ActionRouteGrade
Crouch / standGameplayRestriction.ForceCrouch status effect; the PSM tests the ForceCrouch tag and the sniper nest applies and removes itsource defaultTransition.script:1203, cyberpunk/devices/sniperNest/sniperNest.script:346, 359
JumpInput only: JumpDecisions wakes on a Jump input event and checks IsActionJustPressed(n"Jump") or the JumpPressed conditionsource locomotionTransitions.script:4141-4185
Sprint, dodgeInput only; sprint needs movement input near forwardsource locomotionTransitions.script:1461 onwards
Draw, holster, pick a weapon slotEquipmentSystemWeaponManipulationRequest { owner, requestType: EquipmentManipulationAction } queued on EquipmentSystem (RequestLastUsedOrFirstAvailableWeapon, UnequipWeapon, RequestWeaponSlot1-3, RequestFists…)source orphans.script:11191-11221, 28176-28184, cyberpunk/player/disarmComponent.script:127-135
Consume, healItemActionsHelper.ConsumeItem(executor, itemID, fromInventory), UseHealCharge(executor, itemID)source cyberpunk/items/actions/itemActionsHelper.script:4, 55
Hub menusStartHubMenuEvent.SetStartMenu(n"inventory_screen" | n"world_map" | n"quest_log" | n"new_perks" | n"crafting_main" | n"codex") through GameInstance.GetUISystem(game).QueueEventsource inGameScenarios.script:2-12, inGameMenuGameController.script:501-526, cyberpunk/puppet/scriptedPuppet.script:564-568
WardrobeinkMenuInstance_SpawnEvent.Init(n"OnOpenWardrobeMenu", new WardrobeUserData()) through the UI systemsource cyberpunk/devices/wardrobe/wardrobeController.script:43-53
Close a hub menuForceCloseHubMenuEvent, which the in-game menu turns into OnCloseHubMenuRequestsource inGameMenuGameController.script:274-276
Restrict the playerGameplayRestriction.NoMovement, NoCameraControl, NoJump, NoZooming, NoCombat, NoWorldInteractions, BlockAllHubMenu … as status effectssource 2.31 scripts (usage counts in the design)

6. How input reaches the game, and synthetic input

  • Devices: the executable imports RegisterRawInputDevices and GetRawInputData (keyboard and mouse as Raw Input), XInputGetState from XINPUT9_1_0.dll, HID.DLL functions (other pads), and GetForegroundWindow, ClipCursor, SetCursorPos resource 2.31 executable imports. Posted key messages never reach it and SendInput works only with the game in front runtime sessions 4 and 5 (photo mode §2.3).
  • Where it can be seen: the address library names input::InputSystemWin32Base::Update (hash 261693736) resource; CET uses input::InputSystemWin32Base::ForceCursor (2130646213) and blocks game input by swallowing mouse, keyboard and WM_INPUT messages in its window-procedure hook source CET src/reverse/Addresses.h:62-63, src/d3d12/D3D12.cpp:27-50. Codeware reads decoded input by hooking inkSystem::ProcessInputEvents (hash 673454961), whose RawInputBuffer holds 0x40-byte RawInputData { EInputKey key, EInputAction action, float value, mouseX, mouseY, … } records source Codeware src/App/Callback/Controllers/RawInputHook.hpp, src/Red/Input.hpp.
  • Actions are data. Each action in inputContexts.xml maps to a mapping in inputUserMappings.xml listing keys and pad buttons, for example Choice1 = IK_F or pad X, TogglePhotoMode = IK_N or both sticks clicked (IK_PAD_LR_THUMB) resource inputUserMappings.xml:1175-1200, 2066-2069. Input Loader adds actions by merging r6/input/*.xml (or a plugin's file) into copies in r6/cache and pointing the game at them with engine/config/platform/pc/input_loader.ini; it fires nothing source Input Loader src/Main.cpp. Mods consume actions with RegisterInputListener or by observing PlayerPuppet.OnAction.
  • CDPR's functional-test system is in the retail build. FunctionalTestsGameSystem lists 60 native functions, among them FakeInputPressAction, FakeInputReleaseAction, FakeInputHoldAction, FakeInputClickAction, FakeInputMultitapAction, FakeInputAxisAction, FakeInputReleaseAxisAction, FakePressButton, FakeReleaseButton, FakeSetAxis, TakeOverInput, ReleaseAllInput, LookAtPosition, NavigateFlatTowards, TeleportPlayer, GetPlayerPosition and GetPlayerOrientation; NavigationFunctionalTests has GetPathOnNavmesh, and UIFunctionalTests has Play, IsPlaying and GetPlaybackResult source red-dump-json classes/*FunctionalTests*.json. None has parameters in RTTI (Codeware re-declares them empty) source Codeware 1.20.5 Scripts/Codeware.Global.reds:16732-16791. The retail game doesn't register the system; CET creates it as a singleton for its entity spawner, and adds the missing parameters of WorldFunctionalTests.SpawnEntity itself before calling that native's retail body, kept for mods that still call it source CET src/reverse/RTTIExtender.cpp:341-390, 585-625, 660-667. So the fake-input natives exist and are reachable with CET installed; whether their bodies do anything outside the test engine, and with which parameters, is hypothesis. Recovering a signature means reading the native handler's parameter reads in the executable, the method game crashes §2.1 used.
  • Other channels hypothesis: a virtual XInput pad (replace the XInputGetState import in-process and merge a synthetic state with the real pad's; unknown whether the game polls pads in the background, and it switches its prompts to pad glyphs), or appending records to the decoded buffer before inkSystem::ProcessInputEvents (unknown whether gameplay reads the same buffer).

What the bridge builds on (0.6 and 0.6.1, offline)

  • Refusals first. Every player write reads the PSM blackboard's HighLevel and Locomotion, IsInCombat, VehicleComponent.IsMountedToVehicle and the scene system's IsEntityInScene/IsEntityInDialogue, and refuses with in_combat, in_vehicle, in_scene or player_busy (a jump, slide, swim, workspot, menu or photo mode; named apart from the bridge queue's own busy). 0.6.1 also reads the blackboard's Fall, Landing, Swimming, IsInWorkspot (an Int), Takedown and BodyCarrying (non-zero is busy: gamePSMFallStates, gamePSMLandingState, gamePSMSwimming, gamePSMTakedown, gamePSMBodyCarrying; HighLevel 6 is Swimming) source 2.31 blackboardDefinitions.script:110-162, orphans.script:6647-6980, isInWorkspotPSMPrereq.script:8.
  • Teleport snaps to FindPointInSphereOnlyHumanNavmesh(2 m) after IsNavmeshStreamedInLocation(2 m), keeps within 50 m unless asked, and reads V's place back two ticks later; an instant yaw is a teleport in place; pitch goes through a very short LookAt. Since 0.6.1 the streaming check applies to exact teleports too (any destination more than 0.5 m away).
  • A glide follows CalculatePathOnlyHumanNavmesh's points by a teleport per tick with GameplayRestriction.NoMovement held (and lifted at the end); it plays no walk cycle (whether the third-person body animates is open question 5). Since 0.6.1 it checks V before every step, and ends when the player's own input moves her: while the hold is on, a listener object is registered on V for MoveX, MoveY, Jump, ToggleCrouch, Crouch, ToggleSprint, Sprint, Dodge and the camera axes (GameObject.RegisterInputListener(listener, name), answered through the listener's OnAction, as the takeover system listens for camera input source gameObject.script:152-156, takeOverControlSystem.script:348, 540-570). PlayerPuppet.OnAction itself only sees the actions the puppet registered (player.script:1075-1080), so wrapping it would not see movement. Whether actions still reach a listener while NoMovement holds V is hypothesis until session 7's G2.
  • Crouch is GameplayRestriction.ForceCrouch, remembered so that only the bridge's own is lifted; weapons go through EquipmentSystemWeaponManipulationRequest; menus through StartHubMenuEvent and the wardrobe's spawn event; closing a hub menu with ForceCloseHubMenuEvent through the UI system is hypothesis.
  • The probe reads the functional-test classes' functions (parameter counts and types, registration index) and each native handler's offset from the engine's handler table, without calling anything; its numbers feed the disassembly step of §6.

Open questions

  1. Do the FakeInput* natives work in the retail engine, with which parameters, and without window focus? A read-only probe of their handler offsets, then offline disassembly, then one supervised call (design §2.5).
  2. Does the game poll XInput while its window is not in front?
  3. Does gameplay input read the same decoded buffer that inkSystem::ProcessInputEvents receives?
  4. Can script build an InteractionChoiceEvent that a device accepts from the hub's choice data?
  5. Is the first-person camera's pitch settable directly, or only through LookAt?
  6. Does a per-tick teleport ("glide") play any locomotion animation on V's third-person body, and does it trip area triggers as walking does?

Player-control design · Runtime access · Photo mode · Game crashes · Poses · Mod ecosystem survey

Corrections and credit

This page is generated from knowledge/player-control.md in the repository. If something here is wrong or missing, please open an issue or suggest an edit; links to sources, captures or tests help most.

It builds on the Cyberpunk 2077 modding community’s work. The inline citations link to the wiki pages, mods, tools and repositories each finding came from, and the credits acknowledge everyone we learned from. Citing a source does not mean its authors endorse these notes.