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))
{
Log.Warn("These controls can't be assigned to a second player.");
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));
}
}