3
0

LocalUserSystemComponent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <LocalUserSystemComponent.h>
  9. #include <LocalUser/LocalUserNotificationBus.h>
  10. #include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
  11. #include <AzCore/RTTI/BehaviorContext.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/Serialization/EditContextConstants.inl>
  15. #include <AzCore/std/string/conversions.h>
  16. ////////////////////////////////////////////////////////////////////////////////////////////////////
  17. namespace LocalUser
  18. {
  19. ////////////////////////////////////////////////////////////////////////////////////////////////
  20. class LocalUserNotificationBusBehaviorHandler
  21. : public LocalUserNotificationBus::Handler
  22. , public AZ::BehaviorEBusHandler
  23. {
  24. public:
  25. ////////////////////////////////////////////////////////////////////////////////////////////
  26. AZ_EBUS_BEHAVIOR_BINDER(LocalUserNotificationBusBehaviorHandler, "{6A3B1CAB-92BE-4773-A3AE-470203D70662}", AZ::SystemAllocator
  27. , OnLocalUserSignedIn
  28. , OnLocalUserSignedOut
  29. , OnLocalUserIdAssignedToLocalPlayerSlot
  30. , OnLocalUserIdRemovedFromLocalPlayerSlot
  31. );
  32. ////////////////////////////////////////////////////////////////////////////////////////////
  33. void OnLocalUserSignedIn(AzFramework::LocalUserId localUserId) override
  34. {
  35. Call(FN_OnLocalUserSignedIn, localUserId);
  36. }
  37. ////////////////////////////////////////////////////////////////////////////////////////////
  38. void OnLocalUserSignedOut(AzFramework::LocalUserId localUserId) override
  39. {
  40. Call(FN_OnLocalUserSignedOut, localUserId);
  41. }
  42. ////////////////////////////////////////////////////////////////////////////////////////////
  43. void OnLocalUserIdAssignedToLocalPlayerSlot(AzFramework::LocalUserId localUserId,
  44. AZ::u32 newLocalPlayerSlot,
  45. AZ::u32 previousLocalPlayerSlot) override
  46. {
  47. Call(FN_OnLocalUserIdAssignedToLocalPlayerSlot, localUserId, newLocalPlayerSlot, previousLocalPlayerSlot);
  48. }
  49. ////////////////////////////////////////////////////////////////////////////////////////////
  50. void OnLocalUserIdRemovedFromLocalPlayerSlot(AzFramework::LocalUserId localUserId,
  51. AZ::u32 localPlayerSlot) override
  52. {
  53. Call(FN_OnLocalUserIdRemovedFromLocalPlayerSlot, localUserId, localPlayerSlot);
  54. }
  55. };
  56. ////////////////////////////////////////////////////////////////////////////////////////////////
  57. void LocalUserSystemComponent::Reflect(AZ::ReflectContext* context)
  58. {
  59. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  60. {
  61. serialize->Class<LocalUserSystemComponent, AZ::Component>()
  62. ->Version(0);
  63. if (AZ::EditContext* ec = serialize->GetEditContext())
  64. {
  65. ec->Class<LocalUserSystemComponent>("LocalUser", "Provides functionality for mapping local user ids to local player slots and managing local user profiles.")
  66. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  67. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  68. ;
  69. }
  70. }
  71. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  72. {
  73. behaviorContext->EBus<LocalUserNotificationBus>("LocalUserNotificationBus")
  74. ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
  75. ->Attribute(AZ::Script::Attributes::Category, "LocalUser")
  76. ->Handler<LocalUserNotificationBusBehaviorHandler>()
  77. ;
  78. behaviorContext->EBus<LocalUserRequestBus>("LocalUserRequestBus")
  79. ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
  80. ->Attribute(AZ::Script::Attributes::Category, "LocalUser")
  81. ->Event("GetMaxLocalUsers", &LocalUserRequestBus::Events::GetMaxLocalUsers)
  82. ->Event("IsLocalUserSignedIn", &LocalUserRequestBus::Events::IsLocalUserSignedIn)
  83. ->Event("GetLocalUserName", &LocalUserRequestBus::Events::GetLocalUserName)
  84. ->Event("AssignLocalUserIdToLocalPlayerSlot", &LocalUserRequestBus::Events::AssignLocalUserIdToLocalPlayerSlot)
  85. ->Event("RemoveLocalUserIdFromLocalPlayerSlot", &LocalUserRequestBus::Events::RemoveLocalUserIdFromLocalPlayerSlot)
  86. ->Event("GetLocalUserIdAssignedToLocalPlayerSlot", &LocalUserRequestBus::Events::GetLocalUserIdAssignedToLocalPlayerSlot)
  87. ->Event("GetLocalPlayerSlotOccupiedByLocalUserId", &LocalUserRequestBus::Events::GetLocalPlayerSlotOccupiedByLocalUserId)
  88. ->Event("ClearAllLocalUserIdToLocalPlayerSlotAssignments", &LocalUserRequestBus::Events::ClearAllLocalUserIdToLocalPlayerSlotAssignments)
  89. ;
  90. }
  91. }
  92. ////////////////////////////////////////////////////////////////////////////////////////////////
  93. void LocalUserSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  94. {
  95. provided.push_back(AZ_CRC("LocalUserService"));
  96. }
  97. ////////////////////////////////////////////////////////////////////////////////////////////////
  98. void LocalUserSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  99. {
  100. incompatible.push_back(AZ_CRC("LocalUserService"));
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////////////////////
  103. LocalUserSystemComponent::LocalUserSystemComponent()
  104. {
  105. for (AZ::u32 i = 0; i < LocalPlayerSlotMax; ++i)
  106. {
  107. m_localUserIdsByLocalPlayerSlot[i] = AzFramework::LocalUserIdNone;
  108. }
  109. }
  110. ////////////////////////////////////////////////////////////////////////////////////////////////
  111. void LocalUserSystemComponent::Activate()
  112. {
  113. m_pimpl.reset(Implementation::Create());
  114. LocalUserRequestBus::Handler::BusConnect();
  115. }
  116. ////////////////////////////////////////////////////////////////////////////////////////////////
  117. void LocalUserSystemComponent::Deactivate()
  118. {
  119. ClearAllLocalUserIdToLocalPlayerSlotAssignments();
  120. LocalUserRequestBus::Handler::BusDisconnect();
  121. m_pimpl.reset();
  122. }
  123. ////////////////////////////////////////////////////////////////////////////////////////////////
  124. AZStd::shared_ptr<LocalUserProfile> LocalUserSystemComponent::FindLocalUserProfile(AzFramework::LocalUserId localUserId)
  125. {
  126. return m_pimpl ? m_pimpl->FindLocalUserProfile(localUserId) : nullptr;
  127. }
  128. ////////////////////////////////////////////////////////////////////////////////////////////////
  129. AZ::u32 LocalUserSystemComponent::GetMaxLocalUsers() const
  130. {
  131. if (m_pimpl)
  132. {
  133. return m_pimpl->GetMaxLocalUsers();
  134. }
  135. // On platforms with no concept of a local user profile the local user id corresponds
  136. // to a unique input device index, so the maximum is the number of supported gamepads.
  137. return AzFramework::InputDeviceGamepad::GetMaxSupportedGamepads();
  138. }
  139. ////////////////////////////////////////////////////////////////////////////////////////////////
  140. bool LocalUserSystemComponent::IsLocalUserSignedIn(AzFramework::LocalUserId localUserId)
  141. {
  142. if (m_pimpl)
  143. {
  144. return m_pimpl->IsLocalUserSignedIn(localUserId);
  145. }
  146. // On platforms with no concept of a local user profile the local user id corresponds
  147. // to a unique input device index, and is therefore always considered to be signed in.
  148. return localUserId != AzFramework::LocalUserIdNone;
  149. }
  150. ////////////////////////////////////////////////////////////////////////////////////////////////
  151. AZStd::string LocalUserSystemComponent::GetLocalUserName(AzFramework::LocalUserId localUserId)
  152. {
  153. if (m_pimpl)
  154. {
  155. return m_pimpl->GetLocalUserName(localUserId);
  156. }
  157. // On platforms that have no concept of a local user profile, return "Player N" where "N" is
  158. // the local player slot currently occupied by localUserId, otherwise return an empty string.
  159. const AZ::u32 localPlayerSlot = GetLocalPlayerSlotOccupiedByLocalUserId(localUserId);
  160. return (localPlayerSlot < LocalPlayerSlotMax) ?
  161. AZStd::string("Player ") + AZStd::to_string(localPlayerSlot + 1) :
  162. "";
  163. }
  164. ////////////////////////////////////////////////////////////////////////////////////////////////
  165. AZ::u32 LocalUserSystemComponent::AssignLocalUserIdToLocalPlayerSlot(AzFramework::LocalUserId localUserId,
  166. AZ::u32 localPlayerSlot)
  167. {
  168. AZ_Warning("LocalUserSystemComponent",
  169. localUserId != AzFramework::LocalUserIdAny,
  170. "Assigning LocalUserIdAny to local player slot %d.\n"
  171. "You should likely prompt the user to sign-in first,\n"
  172. "probably by using InputDevice::PromptLocalUserSignIn\n");
  173. const AZ::u32 existingLocalPlayerSlot = GetLocalPlayerSlotOccupiedByLocalUserId(localUserId);
  174. if (localPlayerSlot < LocalPlayerSlotMax)
  175. {
  176. // A specific slot has been requested...
  177. if (m_localUserIdsByLocalPlayerSlot[localPlayerSlot] == AzFramework::LocalUserIdNone)
  178. {
  179. // ...and it is unoccupied, so assign the user into the slot
  180. // and remove the user from any existing slot it occupied.
  181. m_localUserIdsByLocalPlayerSlot[localPlayerSlot] = localUserId;
  182. if (existingLocalPlayerSlot < LocalPlayerSlotMax)
  183. {
  184. m_localUserIdsByLocalPlayerSlot[existingLocalPlayerSlot] = AzFramework::LocalUserIdNone;
  185. }
  186. LocalUserNotificationBus::Broadcast(&LocalUserNotifications::OnLocalUserIdAssignedToLocalPlayerSlot,
  187. localUserId,
  188. localPlayerSlot,
  189. existingLocalPlayerSlot);
  190. return localPlayerSlot;
  191. }
  192. else
  193. {
  194. // ...and it is occupied, so just return the existing slot
  195. // that the user occupies, which may be LocalPlayerSlotNone.
  196. return existingLocalPlayerSlot;
  197. }
  198. }
  199. if (existingLocalPlayerSlot < LocalPlayerSlotMax)
  200. {
  201. // The user is already assigned to a slot and the requested
  202. // slot is already occupied (or any slot was requested).
  203. return existingLocalPlayerSlot;
  204. }
  205. if (localPlayerSlot == LocalPlayerSlotAny)
  206. {
  207. // The user is not already assigned to a slot, and any slot
  208. // was requested, so assign the user to the first empty slot.
  209. for (AZ::u32 i = 0; i < LocalPlayerSlotMax; ++i)
  210. {
  211. if (m_localUserIdsByLocalPlayerSlot[i] == AzFramework::LocalUserIdNone)
  212. {
  213. m_localUserIdsByLocalPlayerSlot[i] = localUserId;
  214. LocalUserNotificationBus::Broadcast(&LocalUserNotifications::OnLocalUserIdAssignedToLocalPlayerSlot,
  215. localUserId,
  216. i,
  217. LocalPlayerSlotNone);
  218. return i;
  219. }
  220. }
  221. }
  222. // Unable to assign the local user id to the requested local player slot
  223. return LocalPlayerSlotNone;
  224. }
  225. ////////////////////////////////////////////////////////////////////////////////////////////////
  226. AZ::u32 LocalUserSystemComponent::RemoveLocalUserIdFromLocalPlayerSlot(AzFramework::LocalUserId localUserId)
  227. {
  228. const AZ::u32 existingLocalPlayerSlot = GetLocalPlayerSlotOccupiedByLocalUserId(localUserId);
  229. if (existingLocalPlayerSlot < LocalPlayerSlotMax)
  230. {
  231. m_localUserIdsByLocalPlayerSlot[existingLocalPlayerSlot] = AzFramework::LocalUserIdNone;
  232. LocalUserNotificationBus::Broadcast(&LocalUserNotifications::OnLocalUserIdRemovedFromLocalPlayerSlot,
  233. localUserId,
  234. existingLocalPlayerSlot);
  235. }
  236. return existingLocalPlayerSlot;
  237. }
  238. ////////////////////////////////////////////////////////////////////////////////////////////////
  239. AzFramework::LocalUserId LocalUserSystemComponent::GetLocalUserIdAssignedToLocalPlayerSlot(AZ::u32 localPlayerSlot)
  240. {
  241. return localPlayerSlot < LocalPlayerSlotMax ?
  242. m_localUserIdsByLocalPlayerSlot[localPlayerSlot] :
  243. AzFramework::LocalUserIdNone;
  244. }
  245. ////////////////////////////////////////////////////////////////////////////////////////////////
  246. AZ::u32 LocalUserSystemComponent::GetLocalPlayerSlotOccupiedByLocalUserId(AzFramework::LocalUserId localUserId)
  247. {
  248. for (AZ::u32 i = 0; i < LocalPlayerSlotMax; ++i)
  249. {
  250. if (m_localUserIdsByLocalPlayerSlot[i] == localUserId)
  251. {
  252. return i;
  253. }
  254. }
  255. return LocalPlayerSlotNone;
  256. }
  257. ////////////////////////////////////////////////////////////////////////////////////////////////
  258. void LocalUserSystemComponent::ClearAllLocalUserIdToLocalPlayerSlotAssignments()
  259. {
  260. for (AZ::u32 i = 0; i < LocalPlayerSlotMax; ++i)
  261. {
  262. const AzFramework::LocalUserId& localUserId = m_localUserIdsByLocalPlayerSlot[i];
  263. if (localUserId != AzFramework::LocalUserIdNone)
  264. {
  265. RemoveLocalUserIdFromLocalPlayerSlot(localUserId);
  266. }
  267. }
  268. }
  269. } // namespace LocalUser