class_name PlayerInputSource extends RefCounted ## Converts remappable Godot Input Map actions into immutable [MoveIntent] values. ## This adapter owns no movement state and may be replaced independently of the ## local movement controller. const RENDER_SANDBOX_PROFILE_ID := &"RenderSandbox" const BLIZZLIKE_335_PROFILE_ID := &"Blizzlike335" var input_profile_id: StringName: get: return _input_profile_id var _input_profile_id: StringName ## Selects one supported action layout. Unknown profiles fail closed to Blizzlike335. func _init(requested_profile_id: StringName = BLIZZLIKE_335_PROFILE_ID) -> void: _input_profile_id = ( RENDER_SANDBOX_PROFILE_ID if requested_profile_id == RENDER_SANDBOX_PROFILE_ID else BLIZZLIKE_335_PROFILE_ID ) ## Samples the current Input singleton state for one physics tick. func sample_move_intent() -> MoveIntent: if _input_profile_id == RENDER_SANDBOX_PROFILE_ID: return compose_move_intent( Input.get_action_strength(PlayerInputActions.MOVE_FORWARD), Input.get_action_strength(PlayerInputActions.MOVE_BACKWARD), Input.get_action_strength(PlayerInputActions.STRAFE_LEFT), Input.get_action_strength(PlayerInputActions.STRAFE_RIGHT), Input.get_action_strength(PlayerInputActions.DEBUG_FLY_UP), Input.get_action_strength(PlayerInputActions.DEBUG_FLY_DOWN), Input.is_action_pressed(PlayerInputActions.DEBUG_SPRINT) ) return compose_blizzlike_335_move_intent( Input.get_action_strength(PlayerInputActions.MOVE_FORWARD), Input.get_action_strength(PlayerInputActions.MOVE_BACKWARD), Input.get_action_strength(PlayerInputActions.BLIZZLIKE_STRAFE_LEFT), Input.get_action_strength(PlayerInputActions.BLIZZLIKE_STRAFE_RIGHT), Input.get_action_strength(PlayerInputActions.TURN_LEFT), Input.get_action_strength(PlayerInputActions.TURN_RIGHT), Input.is_action_pressed(PlayerInputActions.CAMERA_ROTATE) ) ## Builds the compatibility layout: Q/E always strafe; A/D turn unless ## right-mouse camera rotation is active, when A/D also strafe. Default bindings ## come from build 12340; conditional routing is reference-implementation evidence. static func compose_blizzlike_335_move_intent( forward_strength: float, backward_strength: float, strafe_left_strength: float, strafe_right_strength: float, turn_left_strength: float, turn_right_strength: float, camera_rotate_active: bool ) -> MoveIntent: var effective_strafe_left := strafe_left_strength var effective_strafe_right := strafe_right_strength var turn_axis := clampf(turn_right_strength, 0.0, 1.0) - clampf(turn_left_strength, 0.0, 1.0) if camera_rotate_active: effective_strafe_left += turn_left_strength effective_strafe_right += turn_right_strength turn_axis = 0.0 var move_intent := compose_move_intent( forward_strength, backward_strength, effective_strafe_left, effective_strafe_right, 0.0, 0.0, false ) return MoveIntent.new( move_intent.forward_axis, move_intent.strafe_axis, 0.0, false, turn_axis ) ## Builds a normalized sandbox intent from action strengths for deterministic tests and ## alternative input adapters. Strengths outside `[0, 1]` are clamped. static func compose_move_intent( forward_strength: float, backward_strength: float, strafe_left_strength: float, strafe_right_strength: float, fly_up_strength: float, fly_down_strength: float, sprint_requested: bool ) -> MoveIntent: var planar_axis := Vector2( clampf(strafe_right_strength, 0.0, 1.0) - clampf(strafe_left_strength, 0.0, 1.0), clampf(forward_strength, 0.0, 1.0) - clampf(backward_strength, 0.0, 1.0) ) if planar_axis.length_squared() > 1.0: planar_axis = planar_axis.normalized() var vertical_axis := clampf(fly_up_strength, 0.0, 1.0) - clampf(fly_down_strength, 0.0, 1.0) return MoveIntent.new( planar_axis.y, planar_axis.x, vertical_axis, sprint_requested )