- Created AdvancedLoggingExample class demonstrating composite and file loggers - Implemented multi-file logging setup with separate error and full logs - Added game event and performance logging methods - Included key input handling for log operations (flush, clear) - Setup proper resource disposal on application quit
171 lines
6.5 KiB
C#
171 lines
6.5 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.InputSystem.Layouts;
|
||
using UnityEngine.InputSystem.LowLevel;
|
||
|
||
/// <summary>
|
||
/// Мост из твоего фасада In (COM/клава и т.д.) в новый Input System.
|
||
/// Создаёт виртуальный Gamepad и обновляет его состояние на основе:
|
||
/// - действий игроков (PlayerAction), или
|
||
/// - физических пинов (int / ButtonPinMapping)
|
||
/// Выбирай способ через списки маппинга в инспекторе.
|
||
/// </summary>
|
||
[DefaultExecutionOrder(-100)] // пораньше, чтобы UI увидел ввод
|
||
public class ComInputToInputSystemAdapter : MonoBehaviour
|
||
{
|
||
[Header("Источник состояния")]
|
||
[Tooltip("Если true — брать состояние из In.GetButton* AnyPlayer; если false — из CurrentPlayer.")]
|
||
public bool useAnyPlayer = true;
|
||
|
||
[Header("Маппинг по действиям (PlayerAction -> Gamepad)")]
|
||
public List<ActionBinding> actionBindings = new();
|
||
|
||
[Header("Маппинг по пинам (индекс пина -> Gamepad)")]
|
||
public List<PinBinding> 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 нет таких значений — просто пропустим */ }
|
||
}
|
||
} |