MainMenuScreen.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. //-----------------------------------------------------------------------------
  2. // MainMenuScreen.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.GamerServices;
  11. using Microsoft.Xna.Framework.Net;
  12. using Microsoft.Xna.Framework.Graphics;
  13. namespace NetRumble
  14. {
  15. /// <summary>
  16. /// The main menu screen is the first thing displayed when the game starts up.
  17. /// </summary>
  18. public class MainMenuScreen : MenuScreen
  19. {
  20. /// <summary>
  21. /// The potential states of the main menu.
  22. /// </summary>
  23. enum MainMenuState
  24. {
  25. Empty,
  26. SignedOut,
  27. SignedInLocal,
  28. SignedInLive,
  29. }
  30. /// <summary>
  31. /// Flag that tracks last known value of IsTrialMode
  32. /// </summary>
  33. bool trialMode;
  34. bool updateState;
  35. /// <summary>
  36. /// The current state of the main menu.
  37. /// </summary>
  38. MainMenuState state = MainMenuState.Empty;
  39. MainMenuState State
  40. {
  41. get { return state; }
  42. set
  43. {
  44. // exit early from trivial sets
  45. if (state == value && trialMode == Guide.IsTrialMode && !updateState)
  46. {
  47. return;
  48. }
  49. updateState = false; // reset the flag, in case it was set
  50. state = value;
  51. trialMode = Guide.IsTrialMode;
  52. if (MenuEntries != null)
  53. {
  54. switch (state)
  55. {
  56. case MainMenuState.SignedInLive:
  57. {
  58. MenuEntries.Clear();
  59. MenuEntries.Add("Quick Match");
  60. MenuEntries.Add("Create Xbox LIVE Session");
  61. MenuEntries.Add("Join Xbox LIVE Session");
  62. MenuEntries.Add("Create System Link Session");
  63. MenuEntries.Add("Join System Link Session");
  64. if (Guide.IsTrialMode)
  65. {
  66. MenuEntries.Add("Unlock Full Game");
  67. }
  68. else if (ScreenManager.invited != null)
  69. {
  70. MenuEntries.Add("Join Invited Game");
  71. }
  72. MenuEntries.Add("Exit");
  73. break;
  74. }
  75. case MainMenuState.SignedInLocal:
  76. {
  77. MenuEntries.Clear();
  78. MenuEntries.Add("Create LAN Session");
  79. MenuEntries.Add("Join LAN Session");
  80. MenuEntries.Add("Exit");
  81. break;
  82. }
  83. case MainMenuState.SignedOut:
  84. {
  85. MenuEntries.Clear();
  86. MenuEntries.Add("Sign In");
  87. MenuEntries.Add("Exit");
  88. break;
  89. }
  90. }
  91. }
  92. }
  93. }
  94. /// <summary>
  95. /// Constructs a new MainMenu object.
  96. /// </summary>
  97. public MainMenuScreen() : base()
  98. {
  99. // set the transition times
  100. TransitionOnTime = TimeSpan.FromSeconds(1.0);
  101. TransitionOffTime = TimeSpan.FromSeconds(0.0);
  102. // capture current value of trial mode flag
  103. trialMode = Guide.IsTrialMode;
  104. updateState = false;
  105. }
  106. /// <summary>
  107. /// Updates the screen. This method checks the GameScreen.IsActive
  108. /// property, so the game will stop updating when the pause menu is active,
  109. /// or if you tab away to a different application.
  110. /// </summary>
  111. public override void Update(GameTime gameTime, bool otherScreenHasFocus,
  112. bool coveredByOtherScreen)
  113. {
  114. bool signedIntoLive = false;
  115. if (Gamer.SignedInGamers.Count > 0)
  116. {
  117. foreach (SignedInGamer signedInGamer in Gamer.SignedInGamers)
  118. {
  119. if (signedInGamer.IsSignedInToLive)
  120. {
  121. signedIntoLive = true;
  122. break;
  123. }
  124. }
  125. State = signedIntoLive ? MainMenuState.SignedInLive :
  126. MainMenuState.SignedInLocal;
  127. }
  128. else
  129. {
  130. State = MainMenuState.SignedOut;
  131. }
  132. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  133. }
  134. /// <summary>
  135. /// Responds to user menu selections.
  136. /// </summary>
  137. protected override void OnSelectEntry(int entryIndex)
  138. {
  139. switch (state)
  140. {
  141. case MainMenuState.SignedInLive:
  142. {
  143. switch (entryIndex)
  144. {
  145. case 0: // Quick Match
  146. QuickMatchSession();
  147. break;
  148. case 1: // Create Internet Session
  149. CreateSession(NetworkSessionType.PlayerMatch);
  150. break;
  151. case 2: // Join Internet Session
  152. FindSession(NetworkSessionType.PlayerMatch);
  153. break;
  154. case 3: // Create System Link Session
  155. CreateSession(NetworkSessionType.SystemLink);
  156. break;
  157. case 4: // Join System Link Session
  158. FindSession(NetworkSessionType.SystemLink);
  159. break;
  160. case 5: // Exit or Unlock Full Game (depending on trialMode flag)
  161. if (trialMode)
  162. ShowOffer();
  163. else if (ScreenManager.invited != null)
  164. JoinInvitedGame();
  165. else
  166. OnCancel();
  167. break;
  168. case 6: // Exit
  169. OnCancel();
  170. break;
  171. }
  172. break;
  173. }
  174. case MainMenuState.SignedInLocal:
  175. {
  176. switch (entryIndex)
  177. {
  178. case 0: // Create System Link Session
  179. CreateSession(NetworkSessionType.SystemLink);
  180. break;
  181. case 1: // Join System Link Session
  182. FindSession(NetworkSessionType.SystemLink);
  183. break;
  184. case 2: // Exit
  185. OnCancel();
  186. break;
  187. }
  188. break;
  189. }
  190. case MainMenuState.SignedOut:
  191. {
  192. switch (entryIndex)
  193. {
  194. case 0: // Sign In
  195. if (!Guide.IsVisible)
  196. {
  197. Guide.ShowSignIn(1, false);
  198. }
  199. break;
  200. case 1: // Exit
  201. OnCancel();
  202. break;
  203. }
  204. break;
  205. }
  206. }
  207. }
  208. /// <summary>
  209. /// Show the marketplace offer for a trial mode game.
  210. /// </summary>
  211. private void ShowOffer()
  212. {
  213. // NOTE: This chooses the first signed in gamer, since we don't have any information
  214. // about which gamepad clicked on the button.
  215. Guide.ShowMarketplace(Gamer.SignedInGamers[0].PlayerIndex);
  216. }
  217. /// <summary>
  218. /// Attempt to join a session using an invite that was received.
  219. /// </summary>
  220. public void JoinInvitedGame()
  221. {
  222. try
  223. {
  224. // start async join for the invited game
  225. var joinTask = NetworkSession.JoinInvitedAsync(Gamer.SignedInGamers);
  226. var busyScreen = new NetworkBusyScreen<NetworkSession>("Joining the session...", joinTask);
  227. busyScreen.OperationCompleted += InvitedSessionJoined;
  228. ScreenManager.AddScreen(busyScreen);
  229. }
  230. catch
  231. {
  232. // could not begin to join invited game, so default to the pre-existing MainMenuScreen
  233. }
  234. ScreenManager.invited = null;
  235. updateState = true;
  236. }
  237. /// <summary>
  238. /// When the user cancels the main menu, ask if they want to exit the sample.
  239. /// </summary>
  240. protected override void OnCancel()
  241. {
  242. const string message = "Exit Net Rumble?";
  243. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  244. messageBox.Accepted += ExitMessageBoxAccepted;
  245. ScreenManager.AddScreen(messageBox);
  246. }
  247. /// <summary>
  248. /// Event handler for when the user selects ok on the "are you sure
  249. /// you want to exit" message box.
  250. /// </summary>
  251. void ExitMessageBoxAccepted(object sender, EventArgs e)
  252. {
  253. ScreenManager.Game.Exit();
  254. }
  255. /// <summary>
  256. /// Screen-specific update to gamer rich presence.
  257. /// </summary>
  258. public override void UpdatePresence()
  259. {
  260. foreach (SignedInGamer signedInGamer in Gamer.SignedInGamers)
  261. {
  262. if (signedInGamer.IsSignedInToLive)
  263. {
  264. signedInGamer.Presence.PresenceMode = GamerPresenceMode.AtMenu;
  265. }
  266. }
  267. }
  268. private void QuickMatchSession()
  269. {
  270. // start the search
  271. try
  272. {
  273. var findTask = NetworkSession.FindAsync(
  274. NetworkSessionType.PlayerMatch, 1, new Dictionary<string, object>());
  275. var busyScreen = new NetworkBusyScreen<AvailableNetworkSessionCollection>(
  276. "Searching for a session...", findTask);
  277. busyScreen.OperationCompleted += QuickMatchSearchCompleted;
  278. ScreenManager.AddScreen(busyScreen);
  279. }
  280. catch (NetworkException ne)
  281. {
  282. const string message = "Failed searching for the session.";
  283. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  284. messageBox.Accepted += FailedMessageBox;
  285. messageBox.Cancelled += FailedMessageBox;
  286. ScreenManager.AddScreen(messageBox);
  287. System.Console.WriteLine("Failed to search for session: " +
  288. ne.Message);
  289. }
  290. catch (GamerPrivilegeException gpe)
  291. {
  292. const string message =
  293. "You do not have permission to search for a session.";
  294. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  295. messageBox.Accepted += FailedMessageBox;
  296. messageBox.Cancelled += FailedMessageBox;
  297. ScreenManager.AddScreen(messageBox);
  298. System.Console.WriteLine(
  299. "Insufficient privilege to search for session: " + gpe.Message);
  300. }
  301. }
  302. /// <summary>
  303. /// Start creating a session of the given type.
  304. /// </summary>
  305. /// <param name="sessionType">The type of session to create.</param>
  306. void CreateSession(NetworkSessionType sessionType)
  307. {
  308. // create the session
  309. try
  310. {
  311. var createTask = NetworkSession.CreateAsync(sessionType, 1,
  312. World.MaximumPlayers, 0, new Dictionary<string, object>());
  313. var busyScreen = new NetworkBusyScreen<NetworkSession>(
  314. "Creating a session...", createTask);
  315. busyScreen.OperationCompleted += SessionCreated;
  316. ScreenManager.AddScreen(busyScreen);
  317. }
  318. catch (NetworkException ne)
  319. {
  320. const string message = "Failed creating the session.";
  321. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  322. messageBox.Accepted += FailedMessageBox;
  323. messageBox.Cancelled += FailedMessageBox;
  324. ScreenManager.AddScreen(messageBox);
  325. System.Console.WriteLine("Failed to create session: " +
  326. ne.Message);
  327. }
  328. catch (GamerPrivilegeException gpe)
  329. {
  330. const string message =
  331. "You do not have permission to create a session.";
  332. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  333. messageBox.Accepted += FailedMessageBox;
  334. messageBox.Cancelled += FailedMessageBox;
  335. ScreenManager.AddScreen(messageBox);
  336. System.Console.WriteLine(
  337. "Insufficient privilege to create session: " + gpe.Message);
  338. }
  339. }
  340. /// <summary>
  341. /// Start searching for a session of the given type.
  342. /// </summary>
  343. /// <param name="sessionType">The type of session to look for.</param>
  344. void FindSession(NetworkSessionType sessionType)
  345. {
  346. // create the Search screen
  347. ScreenManager.AddScreen(new SearchResultsScreen(sessionType));
  348. }
  349. /// <summary>
  350. /// Callback to receive the network-session search results from quick-match.
  351. /// </summary>
  352. void QuickMatchSearchCompleted(object sender, OperationCompletedEventArgs e)
  353. {
  354. var availableSessions = e.Result as AvailableNetworkSessionCollection;
  355. if (e.Exception != null)
  356. {
  357. string message = e.Exception is GamerPrivilegeException
  358. ? "You do not have permission to search for a session."
  359. : "Failed searching for the session.";
  360. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  361. messageBox.Accepted += FailedMessageBox;
  362. messageBox.Cancelled += FailedMessageBox;
  363. ScreenManager.AddScreen(messageBox);
  364. System.Console.WriteLine("Failed to search for session: " + e.Exception.Message);
  365. return;
  366. }
  367. if ((availableSessions != null) && (availableSessions.Count > 0))
  368. {
  369. try
  370. {
  371. var joinTask = NetworkSession.JoinAsync(availableSessions[0]);
  372. var busyScreen = new NetworkBusyScreen<NetworkSession>(
  373. "Joining the session...", joinTask);
  374. busyScreen.OperationCompleted += QuickMatchSessionJoined;
  375. ScreenManager.AddScreen(busyScreen);
  376. }
  377. catch (Exception ex)
  378. {
  379. const string message = "Failed joining the session.";
  380. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  381. messageBox.Accepted += FailedMessageBox;
  382. messageBox.Cancelled += FailedMessageBox;
  383. ScreenManager.AddScreen(messageBox);
  384. System.Console.WriteLine("Failed to join session: " + ex.Message);
  385. }
  386. }
  387. else
  388. {
  389. const string message = "No matches were found.";
  390. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  391. messageBox.Accepted += FailedMessageBox;
  392. messageBox.Cancelled += FailedMessageBox;
  393. ScreenManager.AddScreen(messageBox);
  394. }
  395. }
  396. /// <summary>
  397. /// Callback when a session is created.
  398. /// </summary>
  399. void SessionCreated(object sender, OperationCompletedEventArgs e)
  400. {
  401. var networkSession = e.Result as NetworkSession;
  402. if (e.Exception != null || networkSession == null)
  403. {
  404. string message = e.Exception is GamerPrivilegeException
  405. ? "You do not have permission to create a session. " + e.Exception.Message
  406. : "Failed creating the session.";
  407. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  408. messageBox.Accepted += FailedMessageBox;
  409. messageBox.Cancelled += FailedMessageBox;
  410. ScreenManager.AddScreen(messageBox);
  411. System.Console.WriteLine("Failed to create session: " + e.Exception?.Message);
  412. return;
  413. }
  414. if (networkSession != null)
  415. {
  416. networkSession.AllowHostMigration = true;
  417. networkSession.AllowJoinInProgress = false;
  418. LoadLobbyScreen(networkSession);
  419. }
  420. }
  421. /// <summary>
  422. /// Callback when a session is quick-matched.
  423. /// </summary>
  424. void QuickMatchSessionJoined(object sender, OperationCompletedEventArgs e)
  425. {
  426. var networkSession = e.Result as NetworkSession;
  427. if (e.Exception != null || networkSession == null)
  428. {
  429. string message = e.Exception is GamerPrivilegeException
  430. ? "You do not have permission to join a session."
  431. : "Failed joining the session.";
  432. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  433. messageBox.Accepted += FailedMessageBox;
  434. messageBox.Cancelled += FailedMessageBox;
  435. ScreenManager.AddScreen(messageBox);
  436. System.Console.WriteLine("Failed to join session: " + e.Exception?.Message);
  437. return;
  438. }
  439. if (networkSession != null)
  440. {
  441. LoadLobbyScreen(networkSession);
  442. }
  443. }
  444. /// <summary>
  445. /// Load the lobby screen with the new session.
  446. /// </summary>
  447. void LoadLobbyScreen(NetworkSession networkSession)
  448. {
  449. if (networkSession != null)
  450. {
  451. LobbyScreen lobbyScreen = new LobbyScreen(networkSession);
  452. lobbyScreen.ScreenManager = this.ScreenManager;
  453. ScreenManager.AddScreen(lobbyScreen);
  454. }
  455. }
  456. /// <summary>
  457. /// Finishes the asynchronous process of joining a game from an invitation,
  458. /// joining the lobby of a hosted game if the join was successful.
  459. /// </summary>
  460. void InvitedSessionJoined(object sender, OperationCompletedEventArgs e)
  461. {
  462. var networkSession = e.Result as NetworkSession;
  463. if (e.Exception != null || networkSession == null)
  464. {
  465. string message = e.Exception is NetworkSessionJoinException je
  466. ? "Failed joining the session (" + je.JoinError.ToString() + ")."
  467. : "Failed joining the session (" + (e.Exception?.Message ?? "Unknown error") + ").";
  468. MessageBoxScreen messageBox = new MessageBoxScreen(message);
  469. messageBox.Accepted += FailedMessageBox;
  470. messageBox.Cancelled += FailedMessageBox;
  471. ScreenManager.AddScreen(messageBox);
  472. System.Console.WriteLine("Failed to join session: " + e.Exception?.Message);
  473. return;
  474. }
  475. // Start the lobby if we got the session!
  476. // Otherwise the MainMenuScreen will be available.
  477. LobbyScreen lobbyScreen = new LobbyScreen(networkSession);
  478. lobbyScreen.ScreenManager = ScreenManager;
  479. ScreenManager.AddScreen(lobbyScreen);
  480. }
  481. /// <summary>
  482. /// Event handler for when the user selects ok on the network-operation-failed
  483. /// message box.
  484. /// </summary>
  485. void FailedMessageBox(object sender, EventArgs e) { }
  486. }
  487. }