summaryrefslogtreecommitdiffstats
path: root/xbmc/games/agents/GameAgentManager.h
blob: 901a492e2359e188387a47de43e4aff5d7f70918 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 *  Copyright (C) 2017-2022 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */
#pragma once

#include "games/GameTypes.h"
#include "input/keyboard/interfaces/IKeyboardDriverHandler.h"
#include "input/mouse/interfaces/IMouseDriverHandler.h"
#include "peripherals/PeripheralTypes.h"
#include "utils/Observer.h"

#include <map>
#include <memory>
#include <set>
#include <string>

class CInputManager;

namespace PERIPHERALS
{
class CPeripheral;
class CPeripherals;
} // namespace PERIPHERALS

namespace KODI
{
namespace JOYSTICK
{
class IInputProvider;
}

namespace GAME
{
class CGameAgent;
class CGameClient;
class CGameClientJoystick;

/*!
 * \brief Class to manage game-playing agents for a running game client
 *
 * Currently, port mapping is controller-based and does not take into account
 * the human belonging to the controller. In the future, humans and possibly
 * bots will be managed here.
 *
 * To map ports to controllers, a list of controllers is retrieved in
 * ProcessJoysticks(). After expired controllers are removed, the port mapping
 * occurs in the static function MapJoysticks(). The strategy is to simply
 * sort controllers by heuristics and greedily assign to game ports.
 */
class CGameAgentManager : public Observable,
                          public Observer,
                          KEYBOARD::IKeyboardDriverHandler,
                          MOUSE::IMouseDriverHandler
{
public:
  CGameAgentManager(PERIPHERALS::CPeripherals& peripheralManager, CInputManager& inputManager);

  virtual ~CGameAgentManager();

  // Lifecycle functions
  void Start(GameClientPtr gameClient);
  void Stop();
  void Refresh();

  // Implementation of Observer
  void Notify(const Observable& obs, const ObservableMessage msg) override;

  // Implementation of IKeyboardDriverHandler
  bool OnKeyPress(const CKey& key) override;
  void OnKeyRelease(const CKey& key) override {}

  // Implementation of IMouseDriverHandler
  bool OnPosition(int x, int y) override;
  bool OnButtonPress(MOUSE::BUTTON_ID button) override;
  void OnButtonRelease(MOUSE::BUTTON_ID button) override {}

private:
  //! @todo De-duplicate these types
  using PortAddress = std::string;
  using JoystickMap = std::map<PortAddress, std::shared_ptr<CGameClientJoystick>>;
  using PortMap = std::map<JOYSTICK::IInputProvider*, std::shared_ptr<CGameClientJoystick>>;

  using PeripheralLocation = std::string;
  using CurrentPortMap = std::map<PortAddress, PeripheralLocation>;
  using CurrentPeripheralMap = std::map<PeripheralLocation, PortAddress>;

  using ControllerAddress = std::string;
  using PeripheralMap = std::map<ControllerAddress, PERIPHERALS::PeripheralPtr>;

  // Internal interface
  void ProcessJoysticks(PERIPHERALS::EventLockHandlePtr& inputHandlingLock);
  void ProcessKeyboard();
  void ProcessMouse();

  // Internal helpers
  void UpdateExpiredJoysticks(const PERIPHERALS::PeripheralVector& joysticks,
                              PERIPHERALS::EventLockHandlePtr& inputHandlingLock);
  void UpdateConnectedJoysticks(const PERIPHERALS::PeripheralVector& joysticks,
                                const PortMap& newPortMap,
                                PERIPHERALS::EventLockHandlePtr& inputHandlingLock,
                                std::set<PERIPHERALS::PeripheralPtr>& disconnectedJoysticks);

  // Static functionals
  static PortMap MapJoysticks(const PERIPHERALS::PeripheralVector& peripheralJoysticks,
                              const JoystickMap& gameClientjoysticks,
                              CurrentPortMap& currentPorts,
                              CurrentPeripheralMap& currentPeripherals,
                              int playerLimit);
  static void MapJoystick(PERIPHERALS::PeripheralPtr peripheralJoystick,
                          std::shared_ptr<CGameClientJoystick> gameClientJoystick,
                          PortMap& result);
  static void LogPeripheralMap(const PeripheralMap& peripheralMap,
                               const std::set<PERIPHERALS::PeripheralPtr>& disconnectedPeripherals);

  // Construction parameters
  PERIPHERALS::CPeripherals& m_peripheralManager;
  CInputManager& m_inputManager;

  // State parameters
  GameClientPtr m_gameClient;
  bool m_bHasKeyboard = false;
  bool m_bHasMouse = false;

  /*!
   * \brief Map of input provider to joystick handler
   *
   * The input provider is a handle to agent input.
   *
   * The joystick handler connects to joystick input of the game client.
   *
   * This property remembers which joysticks are actually being controlled by
   * agents.
   *
   * Not exposed to the game.
   */
  PortMap m_portMap;

  /*!
   * \brief Map of the current ports to their peripheral
   *
   * This allows attempt to preserve player numbers.
   */
  CurrentPortMap m_currentPorts;

  /*!
   * \brief Map of the current peripherals to their port
   *
   * This allows attempt to preserve player numbers.
   */
  CurrentPeripheralMap m_currentPeripherals;

  /*!
   * Map of controller address to source peripheral
   *
   * Source peripherals are not exposed to the game.
   */
  PeripheralMap m_peripheralMap;

  /*!
   * Collection of disconnected joysticks
   *
   * Source peripherals are not exposed to the game.
   */
  std::set<PERIPHERALS::PeripheralPtr> m_disconnectedPeripherals;
};
} // namespace GAME
} // namespace KODI