Download streaming_server_utils/controls.py from lucidml/gta: direct link, hf CLI and curl.
- Browser
- Download file 4.36 kB
-
https://huggingface.co/lucidml/gta/resolve/main/streaming_server_utils/controls.py
- Command line
-
hf download hf://lucidml/gta/streaming_server_utils/controls.py
-
curl -L -o controls.py https://huggingface.co/lucidml/gta/resolve/main/streaming_server_utils/controls.py
4.36 kB
| def _clamp(v: float, lo: float, hi: float) -> float: | |
| return float(max(float(lo), min(float(hi), float(v)))) | |
| def _as_float(v, default: float) -> float: | |
| try: | |
| return float(v) | |
| except Exception: | |
| return float(default) | |
| def _client_schema_5d(state: dict | None) -> list[float]: | |
| """ | |
| Map Next.js/WebRTC client controls to our 5-D action vector: | |
| [forwardBack, strafeLeftRight, turnLeftRight, vertical, boost] | |
| Inputs supported: | |
| - { "pressed": { w,a,s,d,shift,space,left,right } } | |
| - { "pressed_keys": ["w","a",...] } (legacy) | |
| - { | |
| "schemaVersion": "keys+intensity-v1", | |
| "actionVector5d": [f0, f1, f2, f3, f4], | |
| "sensitivity": { | |
| "forwardBack": x, "strafeLeftRight": x, "turnLeftRight": x, "vertical": x, "boost": x | |
| }, | |
| } | |
| Rules (keyboard → axes/buttons): | |
| - axis0 = (w - s) * forwardBack | |
| - axis1 = (d - a) * strafeLeftRight | |
| - axis2 = (right - left) * turnLeftRight | |
| - axis3 = space * vertical | |
| - axis4 = shift * boost | |
| """ | |
| if not isinstance(state, dict): | |
| return [0.0, 0.0, 0.0, 0.0, 0.0] | |
| schema_version = str(state.get("schemaVersion", "")).strip() | |
| vec_direct = state.get("actionVector5d", None) | |
| if schema_version == "keys+intensity-v1" and isinstance(vec_direct, (list, tuple)) and int(len(vec_direct)) == 5: | |
| return [_clamp(_as_float(x, 0.0), -1.0, 1.0) for x in vec_direct] | |
| sens = state.get("sensitivity", None) | |
| if not isinstance(sens, dict): | |
| sens = {} | |
| s_forward = _clamp(_as_float(sens.get("forwardBack", 1.0), 1.0), 0.0, 1.0) | |
| s_strafe = _clamp(_as_float(sens.get("strafeLeftRight", 1.0), 1.0), 0.0, 1.0) | |
| s_turn = _clamp(_as_float(sens.get("turnLeftRight", 1.0), 1.0), 0.0, 1.0) | |
| s_vertical = _clamp(_as_float(sens.get("vertical", 1.0), 1.0), 0.0, 1.0) | |
| s_boost = _clamp(_as_float(sens.get("boost", 1.0), 1.0), 0.0, 1.0) | |
| pressed = state.get("pressed") | |
| if isinstance(pressed, dict): | |
| w = bool(pressed.get("w", False)) | |
| a = bool(pressed.get("a", False)) | |
| s = bool(pressed.get("s", False)) | |
| d = bool(pressed.get("d", False)) | |
| shift = bool(pressed.get("shift", False)) | |
| space = bool(pressed.get("space", False)) | |
| left = bool(pressed.get("left", False)) | |
| right = bool(pressed.get("right", False)) | |
| else: | |
| keys = set(k.lower() for k in state.get("pressed_keys", []) if isinstance(k, str)) | |
| w = ("w" in keys) | |
| a = ("a" in keys) | |
| s = ("s" in keys) | |
| d = ("d" in keys) | |
| shift = ("shift" in keys) | |
| space = ("space" in keys) | |
| left = ("arrowleft" in keys) or ("left" in keys) | |
| right = ("arrowright" in keys) or ("right" in keys) | |
| wv = 1.0 if w else 0.0 | |
| sv = 1.0 if s else 0.0 | |
| av = 1.0 if a else 0.0 | |
| dv = 1.0 if d else 0.0 | |
| lv = 1.0 if left else 0.0 | |
| rv = 1.0 if right else 0.0 | |
| space_v = 1.0 if space else 0.0 | |
| shift_v = 1.0 if shift else 0.0 | |
| axis0 = _clamp((wv - sv) * s_forward, -1.0, 1.0) | |
| axis1 = _clamp((dv - av) * s_strafe, -1.0, 1.0) | |
| axis2 = _clamp((rv - lv) * s_turn, -1.0, 1.0) | |
| axis3 = _clamp(space_v * s_vertical, -1.0, 1.0) | |
| axis4 = _clamp(shift_v * s_boost, -1.0, 1.0) | |
| return [axis0, axis1, axis2, axis3, axis4] | |
| def nextjs_client_actions_to_world_model_5_dim_actions(state: dict | None, *, allow_jump_sprint: bool = False) -> list[float]: | |
| """ | |
| Client controls -> the model's 5-d action: | |
| [forward(W/S), sideways(A/D), sprint, jump, camera_rx] | |
| Signs: +sideways = D, +camera_rx = turning right (arrow right). | |
| allow_jump_sprint=True (the checkpoint config's `jump_sprint`): shift goes to dim 2 (sprint) and space to | |
| dim 3 (jump), with the client's gains applied, clamped to [0, 1]. | |
| allow_jump_sprint=False: dims 2 and 3 are 0 whatever the client sends (space / shift are ignored). | |
| No keys pressed -> the all-zero vector (standing still). | |
| """ | |
| # Client schema (both the key path and actionVector5d): [forwardBack, strafeLeftRight, turnLeftRight, vertical, boost] | |
| v = _client_schema_5d(state) | |
| if allow_jump_sprint: | |
| sprint = _clamp(v[4], 0.0, 1.0) # shift -> dim 2 | |
| jump = _clamp(v[3], 0.0, 1.0) # space -> dim 3 | |
| return [v[0], v[1], sprint, jump, v[2]] | |
| return [v[0], v[1], 0.0, 0.0, v[2]] |