File size: 4,364 Bytes
ae4e95d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 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]] |