using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.LowLevel; /// /// Мост из твоего фасада In (COM/клава и т.д.) в новый Input System. /// Создаёт виртуальный Gamepad и обновляет его состояние на основе: /// - действий игроков (PlayerAction), или /// - физических пинов (int / ButtonPinMapping) /// Выбирай способ через списки маппинга в инспекторе. /// [DefaultExecutionOrder(-100)] // пораньше, чтобы UI увидел ввод public class ComInputToInputSystemAdapter : MonoBehaviour { [Header("Источник состояния")] [Tooltip("Если true — брать состояние из In.GetButton* AnyPlayer; если false — из CurrentPlayer.")] public bool useAnyPlayer = true; [Header("Маппинг по действиям (PlayerAction -> Gamepad)")] public List actionBindings = new(); [Header("Маппинг по пинам (индекс пина -> Gamepad)")] public List pinBindings = new(); [Header("Отладка")] public bool logCreateDevice = true; private static Gamepad _virtualPad; private GamepadState _state; // Защита от дублей при отключённом Domain Reload private static bool _deviceCreated; [Serializable] public struct ActionBinding { public PlayerAction action; // твой enum public TargetTarget target; public GamepadButton button; // если target == Button public DpadDir dpadDirection; // если target == Dpad } [Serializable] public struct PinBinding { public int pinIndex; // твой физический индекс пина public TargetTarget target; public GamepadButton button; // если target == Button public DpadDir dpadDirection; // если target == Dpad } public enum TargetTarget { Button, Dpad } public enum DpadDir { Up, Down, Left, Right } private void Awake() { Initialize(); } private void OnEnable() => Initialize(); private void Update() { if (_virtualPad == null) return; _state = default; // 1) По действиям foreach (ActionBinding b in actionBindings) { bool pressed = useAnyPlayer ? In.GetButtonAnyPlayer(b.action) : In.GetButtonCurrentPlayer(b.action); ApplyBinding(ref _state, b.target, b.button, b.dpadDirection, pressed); } // 2) По пинам foreach (PinBinding b in pinBindings) { bool pressed = In.GetButton(b.pinIndex); ApplyBinding(ref _state, b.target, b.button, b.dpadDirection, pressed); } InputSystem.QueueStateEvent(_virtualPad, _state); // Обновлять InputSystem вручную не нужно (обновится в цикле Unity) } public void Initialize() { EnsureVirtualGamepad(); TryAddDefaultBindingsIfEmpty(); } private static void ApplyBinding(ref GamepadState st, TargetTarget target, GamepadButton btn, DpadDir dir, bool pressed) { if (!pressed) return; if (target == TargetTarget.Button) { st = st.WithButton(btn); } else { st = dir switch { DpadDir.Up => st.WithButton(GamepadButton.DpadUp), DpadDir.Down => st.WithButton(GamepadButton.DpadDown), DpadDir.Left => st.WithButton(GamepadButton.DpadLeft), DpadDir.Right => st.WithButton(GamepadButton.DpadRight), _ => st }; } } private void EnsureVirtualGamepad() { if (_deviceCreated && _virtualPad != null) return; // ищем уже созданный «COM Bridge», чтобы не дублировать foreach (InputDevice dev in InputSystem.devices) { if (dev is not Gamepad { description: { product: "COM Bridge Gamepad" } } gp) continue; _virtualPad = gp; _deviceCreated = true; return; } InputDeviceDescription desc = new() { interfaceName = "Virtual", deviceClass = "Gamepad", product = "COM Bridge Gamepad", manufacturer = "Robotic Retailers" }; _virtualPad = (Gamepad)InputSystem.AddDevice(desc); _deviceCreated = true; if (logCreateDevice) Debug.Log("[InputBridge] Виртуальный Gamepad создан: " + _virtualPad); } private void TryAddDefaultBindingsIfEmpty() { // Если пусто — добавим базовый маппинг стрелок на D-Pad. if (actionBindings.Count != 0) return; TryAddActionBinding(PlayerAction.up, TargetTarget.Dpad, GamepadButton.North, DpadDir.Up); TryAddActionBinding(PlayerAction.down, TargetTarget.Dpad, GamepadButton.South, DpadDir.Down); TryAddActionBinding(PlayerAction.left, TargetTarget.Dpad, GamepadButton.West, DpadDir.Left); TryAddActionBinding(PlayerAction.right, TargetTarget.Dpad, GamepadButton.East, DpadDir.Right); TryAddActionBinding(PlayerAction.action, TargetTarget.Button, GamepadButton.South, DpadDir.Up); TryAddActionBinding(PlayerAction.action, TargetTarget.Button, GamepadButton.East, DpadDir.Up); // SafeTry(() => actionBindings.Add(new ActionBinding { action = PlayerAction.action, target = TargetTarget.Button, button = GamepadButton.South, dpadDirection = DpadDir.Up })); // SafeTry(() => actionBindings.Add(new ActionBinding { action = PlayerAction.extra, target = TargetTarget.Button, button = GamepadButton.East, dpadDirection = DpadDir.Up })); } private void TryAddActionBinding(PlayerAction action, TargetTarget target, GamepadButton btn, DpadDir dir) { SafeTry(() => actionBindings.Add(new ActionBinding { action = action, target = target, button = btn, dpadDirection = dir })); } private static void SafeTry(Action a) { try { a(); } catch { /* если в твоём enum нет таких значений — просто пропустим */ } } }