using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using log4net; using ShipHandling; using UnityEngine; using UnityEngine.InputSystem; using static InputActionMaps; namespace Managers { public class ControlsManager : MonoBehaviour { private static ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Globally accessible member to use manager with. /// public static ControlsManager G { get; private set; } private Dictionary playersControlSchemes = new Dictionary(); public Dictionary unassignedPlayers = new Dictionary(); public EventHandler> PlayerControlAssigned; private ControlSchemeDetection controlSchemeDetector; void Awake() { G = this; Log.Info("Awake"); } public void AssignControlsToPlayers(List players) { playersControlSchemes?.Clear(); foreach (Player p in players) { if (p.character.shipInput != null) { ShipInputHandler input = p.character.shipInput; // TODO: Make this more unique with the GUID and save across more // and different scenarios? playersControlSchemes.Add(p.playerNumber, new UniqueControl() { SchemeName = input.user.controlScheme.Value.name, DeviceId = input.user.pairedDevices[0].deviceId }); // TODO: Show some kind of hint which control scheme this player // is using. // TODO: Needs a possibility to change controls easily. } else { unassignedPlayers.Add(p.playerNumber, p); } } StartControlSchemeDetection(); } public void StartControlSchemeDetection() { controlSchemeDetector = new ControlSchemeDetection(); controlSchemeDetector.ControlSchemeDetected += (obj, uniqueControl) => DetectPlayerControls(uniqueControl); controlSchemeDetector.EnableDetection(); } private void DetectPlayerControls(UniqueControl uc) { if (unassignedPlayers.Count == 0) { controlSchemeDetector.DisableDetection(); Log.Debug("No player without controls left."); return; } int playerId = unassignedPlayers.Keys.First(); if (playersControlSchemes.ContainsValue(uc)) { #if RELEASE Log.Warn("These controls can't be assigned to a second player."); #endif return; } unassignedPlayers[playerId].spawnedCharacter.TryGetComponent(out Ship s); AssignShipControls(uc, s, unassignedPlayers[playerId].character); Log.Info($"Player Number: {playerId} got assigned control scheme: {uc.SchemeName}."); playersControlSchemes.Add(playerId, uc); unassignedPlayers.Remove(playerId); PlayerControlAssigned?.Invoke(this, new Tuple(playerId, uc)); } private void AssignShipControls(UniqueControl uc, Ship s, ShipProperties p) { p.shipInput = new ShipInputHandler(s.state, InputSystem.GetDeviceById(uc.DeviceId), uc.SchemeName); } } } public struct UniqueControl { public string SchemeName; public int DeviceId; /// /// Struct to simply define a control scheme with the device it belongs to. /// /// Name of the control scheme (See Action Maps) /// Id of the device the control belongs to public UniqueControl(string schemeName, int deviceId) { SchemeName = schemeName; DeviceId = deviceId; } } /// /// Listens to all the events defined in the Player action map /// (has multiple schemes across different devices) /// and fires an event with information which device and control scheme /// caused the event. /// public class ControlSchemeDetection : IPlayerActions { InputActionMaps actionMaps; public event EventHandler ControlSchemeDetected; public ControlSchemeDetection() { actionMaps = new InputActionMaps(); actionMaps.Player.SetCallbacks(this); } public void EnableDetection() { actionMaps.Player.Enable(); } public void DisableDetection() { actionMaps.Player.Disable(); } public void OnBoost(InputAction.CallbackContext context) { readControlScheme(context); } public void OnReset(InputAction.CallbackContext context) { readControlScheme(context); } public void OnSteer(InputAction.CallbackContext context) { readControlScheme(context); } public void OnThrust(InputAction.CallbackContext context) { readControlScheme(context); } public void readControlScheme(InputAction.CallbackContext context) { if (!context.canceled || context.performed) { return; } int bindingIndex = context.action.GetBindingIndexForControl(context.control); InputBinding binding = context.action.bindings[bindingIndex]; string controlScheme = binding.groups.Split(';')[0]; ControlSchemeDetected.Invoke(this, new UniqueControl(controlScheme, context.control.device.deviceId)); } }