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 нет таких значений — просто пропустим */ }
}
}