Explorar o código

NetworkStateManagement updated to SDK and MG 3.8.*, but fails ar runtime.

CartBlanche hai 1 semana
pai
achega
56894515e5
Modificáronse 74 ficheiros con 5565 adicións e 5920 borrados
  1. 45 0
      NetworkStateManagement/.vscode/launch.json
  2. 41 0
      NetworkStateManagement/.vscode/tasks.json
  3. 0 0
      NetworkStateManagement/Core/Content/Game.ico
  4. 0 0
      NetworkStateManagement/Core/Content/NetworkStateManagement.png
  5. 0 0
      NetworkStateManagement/Core/Content/background.png
  6. 0 0
      NetworkStateManagement/Core/Content/background.xnb
  7. 0 0
      NetworkStateManagement/Core/Content/blank.png
  8. 0 0
      NetworkStateManagement/Core/Content/blank.xnb
  9. 0 0
      NetworkStateManagement/Core/Content/cat.tga
  10. 0 0
      NetworkStateManagement/Core/Content/cat.xnb
  11. 0 0
      NetworkStateManagement/Core/Content/chat_able.png
  12. 0 0
      NetworkStateManagement/Core/Content/chat_able.xnb
  13. 0 0
      NetworkStateManagement/Core/Content/chat_mute.png
  14. 0 0
      NetworkStateManagement/Core/Content/chat_mute.xnb
  15. 0 0
      NetworkStateManagement/Core/Content/chat_ready.png
  16. 0 0
      NetworkStateManagement/Core/Content/chat_ready.xnb
  17. 0 0
      NetworkStateManagement/Core/Content/chat_talking.png
  18. 0 0
      NetworkStateManagement/Core/Content/chat_talking.xnb
  19. 14 14
      NetworkStateManagement/Core/Content/gamefont.spritefont
  20. 0 0
      NetworkStateManagement/Core/Content/gamefont.xnb
  21. 0 0
      NetworkStateManagement/Core/Content/gradient.png
  22. 0 0
      NetworkStateManagement/Core/Content/gradient.xnb
  23. 14 14
      NetworkStateManagement/Core/Content/menufont.spritefont
  24. 0 0
      NetworkStateManagement/Core/Content/menufont.xnb
  25. 25 29
      NetworkStateManagement/Core/IMessageDisplay.cs
  26. 212 226
      NetworkStateManagement/Core/MessageDisplayComponent.cs
  27. 14 0
      NetworkStateManagement/Core/NetworkStateManagement.Core.csproj
  28. 113 123
      NetworkStateManagement/Core/NetworkStateManagementGame.cs
  29. 101 107
      NetworkStateManagement/Core/Networking/AvailableSessionMenuEntry.cs
  30. 213 0
      NetworkStateManagement/Core/Networking/CreateOrFindSessionScreen.cs
  31. 135 139
      NetworkStateManagement/Core/Networking/JoinSessionScreen.cs
  32. 289 277
      NetworkStateManagement/Core/Networking/LobbyScreen.cs
  33. 154 169
      NetworkStateManagement/Core/Networking/NetworkBusyScreen.cs
  34. 85 89
      NetworkStateManagement/Core/Networking/NetworkErrorScreen.cs
  35. 495 481
      NetworkStateManagement/Core/Networking/NetworkSessionComponent.cs
  36. 32 53
      NetworkStateManagement/Core/Networking/OperationCompletedEventArgs.cs
  37. 177 187
      NetworkStateManagement/Core/Networking/ProfileSignInScreen.cs
  38. 433 433
      NetworkStateManagement/Core/Resources.Designer.cs
  39. 0 0
      NetworkStateManagement/Core/Resources.resources
  40. 249 249
      NetworkStateManagement/Core/Resources.resx
  41. 353 335
      NetworkStateManagement/Core/ScreenManager/GameScreen.cs
  42. 227 237
      NetworkStateManagement/Core/ScreenManager/InputState.cs
  43. 301 315
      NetworkStateManagement/Core/ScreenManager/ScreenManager.cs
  44. 100 110
      NetworkStateManagement/Core/Screens/BackgroundScreen.cs
  45. 283 293
      NetworkStateManagement/Core/Screens/GameplayScreen.cs
  46. 310 306
      NetworkStateManagement/Core/Screens/LoadingScreen.cs
  47. 126 134
      NetworkStateManagement/Core/Screens/MainMenuScreen.cs
  48. 175 191
      NetworkStateManagement/Core/Screens/MenuEntry.cs
  49. 230 244
      NetworkStateManagement/Core/Screens/MenuScreen.cs
  50. 153 167
      NetworkStateManagement/Core/Screens/MessageBoxScreen.cs
  51. 118 123
      NetworkStateManagement/Core/Screens/PauseMenuScreen.cs
  52. 38 42
      NetworkStateManagement/Core/Screens/PlayerIndexEventArgs.cs
  53. 0 180
      NetworkStateManagement/NetworkStateManagement.Linux.csproj
  54. 0 124
      NetworkStateManagement/NetworkStateManagement.MacOS.csproj
  55. 0 188
      NetworkStateManagement/NetworkStateManagement.Windows.csproj
  56. 42 24
      NetworkStateManagement/NetworkStateManagement.sln
  57. 0 210
      NetworkStateManagement/Networking/CreateOrFindSessionScreen.cs
  58. 14 0
      NetworkStateManagement/Platforms/Android/AndroidManifest.xml
  59. 19 0
      NetworkStateManagement/Platforms/Android/MainActivity.cs
  60. 29 0
      NetworkStateManagement/Platforms/Android/NetworkStateManagement.Android.csproj
  61. 0 0
      NetworkStateManagement/Platforms/Android/Program.cs
  62. 29 0
      NetworkStateManagement/Platforms/Desktop/NetworkStateManagement.DesktopGL.csproj
  63. 15 0
      NetworkStateManagement/Platforms/Desktop/Program.cs
  64. 30 0
      NetworkStateManagement/Platforms/Windows/NetworkStateManagement.Windows.csproj
  65. 16 0
      NetworkStateManagement/Platforms/Windows/Program.cs
  66. 19 0
      NetworkStateManagement/Platforms/iOS/AppDelegate.cs
  67. 7 7
      NetworkStateManagement/Platforms/iOS/Info.plist
  68. 29 0
      NetworkStateManagement/Platforms/iOS/NetworkStateManagement.iOS.csproj
  69. 13 0
      NetworkStateManagement/Platforms/iOS/Program.cs
  70. 0 64
      NetworkStateManagement/Program.cs
  71. 0 36
      NetworkStateManagement/Properties/AssemblyInfo.cs
  72. 48 0
      NetworkStateManagement/README.md
  73. 0 0
      NetworkStateManagement/launch.json
  74. 0 0
      NetworkStateManagement/tasks.json

+ 45 - 0
NetworkStateManagement/.vscode/launch.json

@@ -0,0 +1,45 @@
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Launch Windows",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-windows",
+      "program": "${workspaceFolder}/Platforms/Windows/bin/Debug/net8.0-windows/NetworkStateManagement.exe",
+      "args": [],
+      "cwd": "${workspaceFolder}/Platforms/Windows",
+      "stopAtEntry": false
+    },
+    {
+      "name": "Launch DesktopGL",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-desktopgl",
+      "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net8.0/NetworkStateManagement.exe",
+      "args": [],
+      "cwd": "${workspaceFolder}/Platforms/Desktop",
+      "stopAtEntry": false
+    },
+    {
+      "name": "Launch Android",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-android",
+      "program": "${workspaceFolder}/Platforms/Android/bin/Debug/net8.0-android/NetworkStateManagement.Android.dll",
+      "args": [],
+      "cwd": "${workspaceFolder}/Platforms/Android",
+      "stopAtEntry": false
+    },
+    {
+      "name": "Launch iOS",
+      "type": "coreclr",
+      "request": "launch",
+      "preLaunchTask": "build-ios",
+      "program": "${workspaceFolder}/Platforms/iOS/bin/Debug/net8.0-ios/NetworkStateManagement.iOS.dll",
+      "args": [],
+      "cwd": "${workspaceFolder}/Platforms/iOS",
+      "stopAtEntry": false
+    }
+  ]
+}

+ 41 - 0
NetworkStateManagement/.vscode/tasks.json

@@ -0,0 +1,41 @@
+{
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "label": "build-windows",
+      "type": "shell",
+      "command": "dotnet build Platforms/Windows/NetworkStateManagement.Windows.csproj",
+      "group": "build"
+    },
+    {
+      "label": "build-desktopgl",
+      "type": "shell",
+      "command": "dotnet build Platforms/Desktop/NetworkStateManagement.DesktopGL.csproj",
+      "group": "build"
+    },
+    {
+      "label": "build-android",
+      "type": "shell",
+      "command": "dotnet build Platforms/Android/NetworkStateManagement.Android.csproj",
+      "group": "build"
+    },
+    {
+      "label": "build-ios",
+      "type": "shell",
+      "command": "dotnet build Platforms/iOS/NetworkStateManagement.iOS.csproj",
+      "group": "build"
+    },
+    {
+      "label": "run-windows",
+      "type": "shell",
+      "command": "dotnet run --project Platforms/Windows/NetworkStateManagement.Windows.csproj",
+      "group": "test"
+    },
+    {
+      "label": "run-desktopgl",
+      "type": "shell",
+      "command": "dotnet run --project Platforms/Desktop/NetworkStateManagement.DesktopGL.csproj",
+      "group": "test"
+    }
+  ]
+}

+ 0 - 0
NetworkStateManagement/Game.ico → NetworkStateManagement/Core/Content/Game.ico


+ 0 - 0
NetworkStateManagement/NetworkStateManagement.png → NetworkStateManagement/Core/Content/NetworkStateManagement.png


+ 0 - 0
NetworkStateManagement/Content/background.png → NetworkStateManagement/Core/Content/background.png


+ 0 - 0
NetworkStateManagement/Content/background.xnb → NetworkStateManagement/Core/Content/background.xnb


+ 0 - 0
NetworkStateManagement/Content/blank.png → NetworkStateManagement/Core/Content/blank.png


+ 0 - 0
NetworkStateManagement/Content/blank.xnb → NetworkStateManagement/Core/Content/blank.xnb


+ 0 - 0
NetworkStateManagement/Content/cat.tga → NetworkStateManagement/Core/Content/cat.tga


+ 0 - 0
NetworkStateManagement/Content/cat.xnb → NetworkStateManagement/Core/Content/cat.xnb


+ 0 - 0
NetworkStateManagement/Content/chat_able.png → NetworkStateManagement/Core/Content/chat_able.png


+ 0 - 0
NetworkStateManagement/Content/chat_able.xnb → NetworkStateManagement/Core/Content/chat_able.xnb


+ 0 - 0
NetworkStateManagement/Content/chat_mute.png → NetworkStateManagement/Core/Content/chat_mute.png


+ 0 - 0
NetworkStateManagement/Content/chat_mute.xnb → NetworkStateManagement/Core/Content/chat_mute.xnb


+ 0 - 0
NetworkStateManagement/Content/chat_ready.png → NetworkStateManagement/Core/Content/chat_ready.png


+ 0 - 0
NetworkStateManagement/Content/chat_ready.xnb → NetworkStateManagement/Core/Content/chat_ready.xnb


+ 0 - 0
NetworkStateManagement/Content/chat_talking.png → NetworkStateManagement/Core/Content/chat_talking.png


+ 0 - 0
NetworkStateManagement/Content/chat_talking.xnb → NetworkStateManagement/Core/Content/chat_talking.xnb


+ 14 - 14
NetworkStateManagement/Content/gamefont.spritefont → NetworkStateManagement/Core/Content/gamefont.spritefont

@@ -1,15 +1,15 @@
-<?xml version="1.0" encoding="utf-8"?>
-<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
-	<Asset Type="Graphics:FontDescription">
-		<FontName>Segoe UI</FontName>
-		<Size>28</Size>
-		<Spacing>2</Spacing>
-		<Style>Bold</Style>
-		<CharacterRegions>
-			<CharacterRegion>
-				<Start>&#32;</Start>
-				<End>&#126;</End>
-			</CharacterRegion>
-		</CharacterRegions>
-	</Asset>
+<?xml version="1.0" encoding="utf-8"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+	<Asset Type="Graphics:FontDescription">
+		<FontName>Segoe UI</FontName>
+		<Size>28</Size>
+		<Spacing>2</Spacing>
+		<Style>Bold</Style>
+		<CharacterRegions>
+			<CharacterRegion>
+				<Start>&#32;</Start>
+				<End>&#126;</End>
+			</CharacterRegion>
+		</CharacterRegions>
+	</Asset>
 </XnaContent>

+ 0 - 0
NetworkStateManagement/Content/gamefont.xnb → NetworkStateManagement/Core/Content/gamefont.xnb


+ 0 - 0
NetworkStateManagement/Content/gradient.png → NetworkStateManagement/Core/Content/gradient.png


+ 0 - 0
NetworkStateManagement/Content/gradient.xnb → NetworkStateManagement/Core/Content/gradient.xnb


+ 14 - 14
NetworkStateManagement/Content/menufont.spritefont → NetworkStateManagement/Core/Content/menufont.spritefont

@@ -1,15 +1,15 @@
-<?xml version="1.0" encoding="utf-8"?>
-<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
-	<Asset Type="Graphics:FontDescription">
-		<FontName>Segoe UI Mono</FontName>
-		<Size>20</Size>
-		<Spacing>2</Spacing>
-		<Style>Regular</Style>
-		<CharacterRegions>
-			<CharacterRegion>
-				<Start>&#32;</Start>
-				<End>&#126;</End>
-			</CharacterRegion>
-		</CharacterRegions>
-	</Asset>
+<?xml version="1.0" encoding="utf-8"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+	<Asset Type="Graphics:FontDescription">
+		<FontName>Segoe UI Mono</FontName>
+		<Size>20</Size>
+		<Spacing>2</Spacing>
+		<Style>Regular</Style>
+		<CharacterRegions>
+			<CharacterRegion>
+				<Start>&#32;</Start>
+				<End>&#126;</End>
+			</CharacterRegion>
+		</CharacterRegions>
+	</Asset>
 </XnaContent>

+ 0 - 0
NetworkStateManagement/Content/menufont.xnb → NetworkStateManagement/Core/Content/menufont.xnb


+ 25 - 29
NetworkStateManagement/IMessageDisplay.cs → NetworkStateManagement/Core/IMessageDisplay.cs

@@ -1,29 +1,25 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// IMessageDisplay.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// Interface used to display notification messages when interesting events occur,
-	/// for instance when gamers join or leave the network session. This interface
-	/// is registered as a service, so any piece of code wanting to display a message
-	/// can look it up from Game.Services, without needing to worry about how the
-	/// message display is implemented. In this sample, the MessageDisplayComponent
-	/// class implement this IMessageDisplay service.
-	/// </summary>
-	interface IMessageDisplay : IDrawable, IUpdateable
-	{
-		void ShowMessage (string message, params object[] parameters);
-	}
-}
+//-----------------------------------------------------------------------------
+// IMessageDisplay.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// Interface used to display notification messages when interesting events occur,
+	/// for instance when gamers join or leave the network session. This interface
+	/// is registered as a service, so any piece of code wanting to display a message
+	/// can look it up from Game.Services, without needing to worry about how the
+	/// message display is implemented. In this sample, the MessageDisplayComponent
+	/// class implement this IMessageDisplay service.
+	/// </summary>
+	interface IMessageDisplay : IDrawable, IUpdateable
+	{
+		void ShowMessage(string message, params object[] parameters);
+	}
+}

+ 212 - 226
NetworkStateManagement/MessageDisplayComponent.cs → NetworkStateManagement/Core/MessageDisplayComponent.cs

@@ -1,226 +1,212 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MessageDisplayComponent.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Component implements the IMessageDisplay interface. This is used to show
-    /// notification messages when interesting events occur, for instance when
-    /// gamers join or leave the network session
-    /// </summary>
-    class MessageDisplayComponent : DrawableGameComponent, IMessageDisplay
-    {
-        #region Fields
-
-        SpriteBatch spriteBatch;
-        SpriteFont font;
-
-        // List of the currently visible notification messages.
-        List<NotificationMessage> messages = new List<NotificationMessage>();
-
-        // Coordinates threadsafe access to the message list.
-        object syncObject = new object();
-
-        // Tweakable settings control how long each message is visible.
-        static readonly TimeSpan fadeInTime = TimeSpan.FromSeconds(0.25);
-        static readonly TimeSpan showTime = TimeSpan.FromSeconds(5);
-        static readonly TimeSpan fadeOutTime = TimeSpan.FromSeconds(0.5);
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new message display component.
-        /// </summary>
-        public MessageDisplayComponent(Game game)
-            : base(game)
-        {
-            // Register ourselves to implement the IMessageDisplay service.
-            game.Services.AddService(typeof(IMessageDisplay), this);
-        }
-
-
-        /// <summary>
-        /// Load graphics content for the message display.
-        /// </summary>
-        protected override void LoadContent()
-        {
-            spriteBatch = new SpriteBatch(GraphicsDevice);
-
-            font = Game.Content.Load<SpriteFont>("menufont");
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the message display component.
-        /// </summary>
-        public override void Update(GameTime gameTime)
-        {
-            lock (syncObject)
-            {
-                int index = 0;
-                float targetPosition = 0;
-
-                // Update each message in turn.
-                while (index < messages.Count)
-                {
-                    NotificationMessage message = messages[index];
-
-                    // Gradually slide the message toward its desired position.
-                    float positionDelta = targetPosition - message.Position;
-
-                    float velocity = (float)gameTime.ElapsedGameTime.TotalSeconds * 2;
-
-                    message.Position += positionDelta * Math.Min(velocity, 1);
-
-                    // Update the age of the message.
-                    message.Age += gameTime.ElapsedGameTime;
-
-                    if (message.Age < showTime + fadeOutTime)
-                    {
-                        // This message is still alive.
-                        index++;
-
-                        // Any subsequent messages should be positioned below
-                        // this one, unless it has started to fade out.
-                        if (message.Age < showTime)
-                            targetPosition++;
-                    }
-                    else
-                    {
-                        // This message is old, and should be removed.
-                        messages.RemoveAt(index);
-                    }
-                }
-            }
-        }
-
-
-        /// <summary>
-        /// Draws the message display component.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            lock (syncObject)
-            {
-                // Early out if there are no messages to display.
-                if (messages.Count == 0)
-                    return;
-
-                Vector2 position = new Vector2(GraphicsDevice.Viewport.Width - 100, 0);
-
-                spriteBatch.Begin();
-
-                // Draw each message in turn.
-                foreach (NotificationMessage message in messages)
-                {
-                    const float scale = 0.75f;
-
-                    // Compute the alpha of this message.
-                    float alpha = 1;
-
-                    if (message.Age < fadeInTime)
-                    {
-                        // Fading in.
-                        alpha = (float)(message.Age.TotalSeconds /
-                                        fadeInTime.TotalSeconds);
-                    }
-                    else if (message.Age > showTime)
-                    {
-                        // Fading out.
-                        TimeSpan fadeOut = showTime + fadeOutTime - message.Age;
-
-                        alpha = (float)(fadeOut.TotalSeconds /
-                                        fadeOutTime.TotalSeconds);
-                    }
-
-                    // Compute the message position.
-                    position.Y = 80 + message.Position * font.LineSpacing * scale;
-
-                    // Compute an origin value to right align each message.
-                    Vector2 origin = font.MeasureString(message.Text);
-                    origin.Y = 0;
-
-                    // Draw the message text, with a drop shadow.
-                    spriteBatch.DrawString(font, message.Text, position + Vector2.One,
-                                           Color.Black * alpha, 0,
-                                           origin, scale, SpriteEffects.None, 0);
-
-                    spriteBatch.DrawString(font, message.Text, position,
-                                           Color.White * alpha, 0,
-                                           origin, scale, SpriteEffects.None, 0);
-                }
-
-                spriteBatch.End();
-            }
-        }
-
-
-        #endregion
-
-        #region Implement IMessageDisplay
-
-
-        /// <summary>
-        /// Shows a new notification message.
-        /// </summary>
-        public void ShowMessage(string message, params object[] parameters)
-        {
-            string formattedMessage = string.Format(message, parameters);
-
-            lock (syncObject)
-            {
-                float startPosition = messages.Count;
-
-                messages.Add(new NotificationMessage(formattedMessage, startPosition));
-            }
-        }
-
-
-        #endregion
-
-        #region Nested Types
-
-
-        /// <summary>
-        /// Helper class stores the position and text of a single notification message.
-        /// </summary>
-        class NotificationMessage
-        {
-            public string Text;
-            public float Position;
-            public TimeSpan Age;
-
-
-            public NotificationMessage(string text, float position)
-            {
-                Text = text;
-                Position = position;
-                Age = TimeSpan.Zero;
-            }
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MessageDisplayComponent.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Component implements the IMessageDisplay interface. This is used to show
+    /// notification messages when interesting events occur, for instance when
+    /// gamers join or leave the network session
+    /// </summary>
+    class MessageDisplayComponent : DrawableGameComponent, IMessageDisplay
+    {
+
+        SpriteBatch spriteBatch;
+        SpriteFont font;
+
+        // List of the currently visible notification messages.
+        List<NotificationMessage> messages = new List<NotificationMessage>();
+
+        // Coordinates threadsafe access to the message list.
+        object syncObject = new object();
+
+        // Tweakable settings control how long each message is visible.
+        static readonly TimeSpan fadeInTime = TimeSpan.FromSeconds(0.25);
+        static readonly TimeSpan showTime = TimeSpan.FromSeconds(5);
+        static readonly TimeSpan fadeOutTime = TimeSpan.FromSeconds(0.5);
+
+
+
+
+        /// <summary>
+        /// Constructs a new message display component.
+        /// </summary>
+        public MessageDisplayComponent(Game game)
+            : base(game)
+        {
+            // Register ourselves to implement the IMessageDisplay service.
+            game.Services.AddService(typeof(IMessageDisplay), this);
+        }
+
+
+        /// <summary>
+        /// Load graphics content for the message display.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            spriteBatch = new SpriteBatch(GraphicsDevice);
+
+            font = Game.Content.Load<SpriteFont>("menufont");
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the message display component.
+        /// </summary>
+        public override void Update(GameTime gameTime)
+        {
+            lock (syncObject)
+            {
+                int index = 0;
+                float targetPosition = 0;
+
+                // Update each message in turn.
+                while (index < messages.Count)
+                {
+                    NotificationMessage message = messages[index];
+
+                    // Gradually slide the message toward its desired position.
+                    float positionDelta = targetPosition - message.Position;
+
+                    float velocity = (float)gameTime.ElapsedGameTime.TotalSeconds * 2;
+
+                    message.Position += positionDelta * Math.Min(velocity, 1);
+
+                    // Update the age of the message.
+                    message.Age += gameTime.ElapsedGameTime;
+
+                    if (message.Age < showTime + fadeOutTime)
+                    {
+                        // This message is still alive.
+                        index++;
+
+                        // Any subsequent messages should be positioned below
+                        // this one, unless it has started to fade out.
+                        if (message.Age < showTime)
+                            targetPosition++;
+                    }
+                    else
+                    {
+                        // This message is old, and should be removed.
+                        messages.RemoveAt(index);
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the message display component.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            lock (syncObject)
+            {
+                // Early out if there are no messages to display.
+                if (messages.Count == 0)
+                    return;
+
+                Vector2 position = new Vector2(GraphicsDevice.Viewport.Width - 100, 0);
+
+                spriteBatch.Begin();
+
+                // Draw each message in turn.
+                foreach (NotificationMessage message in messages)
+                {
+                    const float scale = 0.75f;
+
+                    // Compute the alpha of this message.
+                    float alpha = 1;
+
+                    if (message.Age < fadeInTime)
+                    {
+                        // Fading in.
+                        alpha = (float)(message.Age.TotalSeconds /
+                                        fadeInTime.TotalSeconds);
+                    }
+                    else if (message.Age > showTime)
+                    {
+                        // Fading out.
+                        TimeSpan fadeOut = showTime + fadeOutTime - message.Age;
+
+                        alpha = (float)(fadeOut.TotalSeconds /
+                                        fadeOutTime.TotalSeconds);
+                    }
+
+                    // Compute the message position.
+                    position.Y = 80 + message.Position * font.LineSpacing * scale;
+
+                    // Compute an origin value to right align each message.
+                    Vector2 origin = font.MeasureString(message.Text);
+                    origin.Y = 0;
+
+                    // Draw the message text, with a drop shadow.
+                    spriteBatch.DrawString(font, message.Text, position + Vector2.One,
+                                           Color.Black * alpha, 0,
+                                           origin, scale, SpriteEffects.None, 0);
+
+                    spriteBatch.DrawString(font, message.Text, position,
+                                           Color.White * alpha, 0,
+                                           origin, scale, SpriteEffects.None, 0);
+                }
+
+                spriteBatch.End();
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Shows a new notification message.
+        /// </summary>
+        public void ShowMessage(string message, params object[] parameters)
+        {
+            string formattedMessage = string.Format(message, parameters);
+
+            lock (syncObject)
+            {
+                float startPosition = messages.Count;
+
+                messages.Add(new NotificationMessage(formattedMessage, startPosition));
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Helper class stores the position and text of a single notification message.
+        /// </summary>
+        class NotificationMessage
+        {
+            public string Text;
+            public float Position;
+            public TimeSpan Age;
+
+
+            public NotificationMessage(string text, float position)
+            {
+                Text = text;
+                Position = position;
+                Age = TimeSpan.Zero;
+            }
+        }
+
+
+    }
+}

+ 14 - 0
NetworkStateManagement/Core/NetworkStateManagement.Core.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <RootNamespace>NetworkStateManagement.Core</RootNamespace>
+    <AssemblyName>NetworkStateManagement.Core</AssemblyName>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+    <ProjectReference Include="..\..\MonoGame.Xna.Framework.Net\MonoGame.Xna.Framework.Net.csproj" />
+  </ItemGroup>
+
+</Project>

+ 113 - 123
NetworkStateManagement/Game.cs → NetworkStateManagement/Core/NetworkStateManagementGame.cs

@@ -1,123 +1,113 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// Game.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.GamerServices;
-using Microsoft.Xna.Framework.Net;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// Sample showing how to manage the different game states involved in
-	/// implementing a networked game, with menus for creating, searching,
-	/// and joining sessions, a lobby screen, and the game itself. This main
-	/// game class is extremely simple: all the interesting stuff happens
-	/// in the ScreenManager component.
-	/// </summary>
-	public class NetworkStateManagementGame : Microsoft.Xna.Framework.Game
-	{
-	#region Fields
-
-		GraphicsDeviceManager graphics;
-		ScreenManager screenManager;
-
-
-		// By preloading any assets used by UI rendering, we avoid framerate glitches
-		// when they suddenly need to be loaded in the middle of a menu transition.
-		static readonly string[] preloadAssets = 
-	{
-		"gradient",
-		"cat",
-		"chat_ready",
-		"chat_able",
-		"chat_talking",
-		"chat_mute",
-	};
-
-
-	#endregion
-
-	#region Initialization
-
-        /// <summary>
-		/// The main game constructor.
-		/// </summary>		
-#if ANDROID 
-		public NetworkStateManagementGame  (Activity activity) : base (activity)
-#else 
-        public NetworkStateManagementGame  ()  
-#endif
-		{
-			Content.RootDirectory = "Content";
-
-			graphics = new GraphicsDeviceManager (this);            
-#if ANDROID
-            graphics.IsFullScreen = true;
-#else
-            graphics.PreferredBackBufferWidth = 1067;
-			graphics.PreferredBackBufferHeight = 600;
-#endif
-
-			// Create components.
-			screenManager = new ScreenManager (this);
-
-			Components.Add (screenManager);
-			Components.Add (new MessageDisplayComponent (this));
-			Components.Add (new GamerServicesComponent (this));
-
-			// Activate the first screens.
-			screenManager.AddScreen (new BackgroundScreen (), null);
-			screenManager.AddScreen (new MainMenuScreen (), null);
-
-			// Listen for invite notification events.
-			NetworkSession.InviteAccepted += (sender, e) => NetworkSessionComponent.InviteAccepted (screenManager, e);
-
-			// To test the trial mode behavior while developing your game,
-			// uncomment this line:
-
-			// Guide.SimulateTrialMode = true;
-		}
-
-
-		/// <summary>
-		/// Loads graphics content.
-		/// </summary>
-		protected override void LoadContent ()
-		{
-			foreach (string asset in preloadAssets) {
-				Content.Load<object> (asset);
-			}
-		}
-
-
-	#endregion
-
-	#region Draw
-
-
-		/// <summary>
-		/// This is called when the game should draw itself.
-		/// </summary>
-		protected override void Draw (GameTime gameTime)
-		{
-			graphics.GraphicsDevice.Clear (Color.Black);
-
-			// The real drawing happens inside the screen manager component.
-			base.Draw (gameTime);
-		}
-
-
-	#endregion
-	}
-
-}
+//-----------------------------------------------------------------------------
+// Game.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Net;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// Sample showing how to manage the different game states involved in
+	/// implementing a networked game, with menus for creating, searching,
+	/// and joining sessions, a lobby screen, and the game itself. This main
+	/// game class is extremely simple: all the interesting stuff happens
+	/// in the ScreenManager component.
+	/// </summary>
+	public class NetworkStateManagementGame : Game
+	{
+
+		GraphicsDeviceManager graphics;
+		ScreenManager screenManager;
+
+
+		// By preloading any assets used by UI rendering, we avoid framerate glitches
+		// when they suddenly need to be loaded in the middle of a menu transition.
+		static readonly string[] preloadAssets =
+	{
+		"gradient",
+		"cat",
+		"chat_ready",
+		"chat_able",
+		"chat_talking",
+		"chat_mute",
+	};
+
+
+
+
+		/// <summary>
+		/// The main game constructor.
+		/// </summary>		
+#if ANDROID
+		public NetworkStateManagementGame  (Activity activity) : base (activity)
+#else
+		public NetworkStateManagementGame()
+#endif
+		{
+			Content.RootDirectory = "Content";
+
+			graphics = new GraphicsDeviceManager(this);
+#if MOBILE
+			graphics.IsFullScreen = true;
+#endif
+			graphics.PreferredBackBufferWidth = 1067;
+			graphics.PreferredBackBufferHeight = 600;
+
+			// Create components.
+			screenManager = new ScreenManager(this);
+
+			Components.Add(screenManager);
+			Components.Add(new MessageDisplayComponent(this));
+			Components.Add(new GamerServicesComponent(this));
+
+			// Activate the first screens.
+			screenManager.AddScreen(new BackgroundScreen(), null);
+			screenManager.AddScreen(new MainMenuScreen(), null);
+
+			// Listen for invite notification events.
+			NetworkSession.InviteAccepted += (sender, e) => NetworkSessionComponent.InviteAccepted(screenManager, e);
+
+			// To test the trial mode behavior while developing your game,
+			// uncomment this line:
+
+			// Guide.SimulateTrialMode = true;
+		}
+
+
+		/// <summary>
+		/// Loads graphics content.
+		/// </summary>
+		protected override void LoadContent()
+		{
+			foreach (string asset in preloadAssets)
+			{
+				Content.Load<object>(asset);
+			}
+		}
+
+
+
+
+
+		/// <summary>
+		/// This is called when the game should draw itself.
+		/// </summary>
+		protected override void Draw(GameTime gameTime)
+		{
+			graphics.GraphicsDevice.Clear(Color.Black);
+
+			// The real drawing happens inside the screen manager component.
+			base.Draw(gameTime);
+		}
+
+
+	}
+
+}

+ 101 - 107
NetworkStateManagement/Networking/AvailableSessionMenuEntry.cs → NetworkStateManagement/Core/Networking/AvailableSessionMenuEntry.cs

@@ -1,107 +1,101 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// AvailableSessionMenuEntry.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// Helper class customizes the standard MenuEntry class
-	/// for displaying AvailableNetworkSession objects.
-	/// </summary>
-	class AvailableSessionMenuEntry : MenuEntry
-	{
-	#region Fields
-
-		AvailableNetworkSession availableSession;
-		bool gotQualityOfService;
-
-	#endregion
-
-	#region Properties
-
-
-		/// <summary>
-		/// Gets the available network session corresponding to this menu entry.
-		/// </summary>
-		public AvailableNetworkSession AvailableSession {
-			get { return availableSession; }
-		}
-
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructs a menu entry describing an available network session.
-		/// </summary>
-		public AvailableSessionMenuEntry (AvailableNetworkSession availableSession)
-		: base(GetMenuItemText(availableSession))
-			{
-			this.availableSession = availableSession;
-		}
-
-
-		/// <summary>
-		/// Formats session information to create the menu text string.
-		/// </summary>
-		static string GetMenuItemText (AvailableNetworkSession session)
-		{
-			int totalSlots = session.CurrentGamerCount + 
-				session.OpenPublicGamerSlots;
-
-			return string.Format ("{0} ({1}/{2})", session.HostGamertag, 
-						session.CurrentGamerCount, 
-						totalSlots);
-		}
-
-
-	#endregion
-
-	#region Update
-
-
-		/// <summary>
-		/// Updates the menu item text, adding information about the network
-		/// quality of service as soon as that becomes available.
-		/// </summary>
-		public override void Update (MenuScreen screen, bool isSelected, 
-							GameTime gameTime)
-		{
-			base.Update (screen, isSelected, gameTime);
-
-			// Quality of service data can take some time to query, so it will not
-			// be filled in straight away when NetworkSession.Find returns. We want
-			// to display the list of available sessions straight away, and then
-			// fill in the quality of service data whenever that becomes available,
-			// so we keep checking until this data shows up.
-			if (screen.IsActive && !gotQualityOfService) {
-				QualityOfService qualityOfService = availableSession.QualityOfService;
-
-				if (qualityOfService.IsAvailable) {
-					TimeSpan pingTime = qualityOfService.AverageRoundtripTime;
-
-					Text += string.Format (" - {0:0} ms", pingTime.TotalMilliseconds);
-
-					gotQualityOfService = true;
-				}
-			}
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// AvailableSessionMenuEntry.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// Helper class customizes the standard MenuEntry class
+	/// for displaying AvailableNetworkSession objects.
+	/// </summary>
+	class AvailableSessionMenuEntry : MenuEntry
+	{
+
+		AvailableNetworkSession availableSession;
+		bool gotQualityOfService;
+
+
+
+
+		/// <summary>
+		/// Gets the available network session corresponding to this menu entry.
+		/// </summary>
+		public AvailableNetworkSession AvailableSession
+		{
+			get { return availableSession; }
+		}
+
+
+
+
+
+		/// <summary>
+		/// Constructs a menu entry describing an available network session.
+		/// </summary>
+		public AvailableSessionMenuEntry(AvailableNetworkSession availableSession)
+		: base(GetMenuItemText(availableSession))
+		{
+			this.availableSession = availableSession;
+		}
+
+
+		/// <summary>
+		/// Formats session information to create the menu text string.
+		/// </summary>
+		static string GetMenuItemText(AvailableNetworkSession session)
+		{
+			int totalSlots = session.CurrentGamerCount +
+				session.OpenPublicGamerSlots;
+
+			return string.Format("{0} ({1}/{2})", session.HostGamertag,
+						session.CurrentGamerCount,
+						totalSlots);
+		}
+
+
+
+
+
+		/// <summary>
+		/// Updates the menu item text, adding information about the network
+		/// quality of service as soon as that becomes available.
+		/// </summary>
+		public override void Update(MenuScreen screen, bool isSelected,
+							GameTime gameTime)
+		{
+			base.Update(screen, isSelected, gameTime);
+
+			// Quality of service data can take some time to query, so it will not
+			// be filled in straight away when NetworkSession.Find returns. We want
+			// to display the list of available sessions straight away, and then
+			// fill in the quality of service data whenever that becomes available,
+			// so we keep checking until this data shows up.
+			if (screen.IsActive && !gotQualityOfService)
+			{
+				QualityOfService qualityOfService = availableSession.QualityOfService;
+
+				if (qualityOfService.IsAvailable)
+				{
+					// TODO: Check if the compatibility layer supports AverageRoundtripTime
+					// For now, show a default ping time
+					TimeSpan pingTime = TimeSpan.FromMilliseconds(50); // Default 50ms ping
+																	   // TimeSpan pingTime = qualityOfService.AverageRoundtripTime;
+
+					Text += string.Format(" - {0:0} ms", pingTime.TotalMilliseconds);
+
+					gotQualityOfService = true;
+				}
+			}
+		}
+
+
+	}
+}

+ 213 - 0
NetworkStateManagement/Core/Networking/CreateOrFindSessionScreen.cs

@@ -0,0 +1,213 @@
+//-----------------------------------------------------------------------------
+// CreateOrFindSessionScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+using Microsoft.Xna.Framework.GamerServices;
+using System.Threading.Tasks;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// This menu screen lets the user choose whether to create a new
+	/// network session, or search for an existing session to join.
+	/// </summary>
+	class CreateOrFindSessionScreen : MenuScreen
+	{
+
+		NetworkSessionType sessionType;
+
+
+
+
+		/// <summary>
+		/// Constructor fills in the menu contents.
+		/// </summary>
+		public CreateOrFindSessionScreen(NetworkSessionType sessionType)
+		: base(GetMenuTitle(sessionType))
+		{
+			this.sessionType = sessionType;
+
+			// Create our menu entries.
+			MenuEntry createSessionMenuEntry = new MenuEntry(Resources.CreateSession);
+			MenuEntry findSessionsMenuEntry = new MenuEntry(Resources.FindSessions);
+			MenuEntry backMenuEntry = new MenuEntry(Resources.Back);
+
+			// Hook up menu event handlers.
+			createSessionMenuEntry.Selected += CreateSessionMenuEntrySelected;
+			findSessionsMenuEntry.Selected += FindSessionsMenuEntrySelected;
+			backMenuEntry.Selected += OnCancel;
+
+			// Add entries to the menu.
+			MenuEntries.Add(createSessionMenuEntry);
+			MenuEntries.Add(findSessionsMenuEntry);
+			MenuEntries.Add(backMenuEntry);
+		}
+
+
+		/// <summary>
+		/// Helper chooses an appropriate menu title for the specified session type.
+		/// </summary>
+		static string GetMenuTitle(NetworkSessionType sessionType)
+		{
+			switch (sessionType)
+			{
+				case NetworkSessionType.PlayerMatch:
+					return Resources.PlayerMatch;
+
+				case NetworkSessionType.SystemLink:
+					return Resources.SystemLink;
+
+				default:
+					throw new NotSupportedException();
+			}
+		}
+
+		/// <summary>
+		/// Event handler for when the Create Session menu entry is selected.
+		/// </summary>
+		void CreateSessionMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			try
+			{
+				// Which local profiles should we include in this session?
+				IEnumerable<SignedInGamer> localGamers = NetworkSessionComponent.ChooseGamers(sessionType, ControllingPlayer.Value);
+
+				// Begin an asynchronous create network session operation.
+				var networkSession = NetworkSession.CreateAsync(
+						sessionType,
+						NetworkSessionComponent.MaxLocalGamers,
+						NetworkSessionComponent.MaxGamers,
+						1,
+						null);
+
+				// Activate the network busy screen, which will display
+				// an animation until this operation has completed.
+				NetworkBusyScreen busyScreen = new NetworkBusyScreen(networkSession);
+
+				busyScreen.OperationCompleted += CreateSessionOperationCompleted;
+
+				ScreenManager.AddScreen(busyScreen, ControllingPlayer);
+			}
+			catch (Exception exception)
+			{
+				NetworkErrorScreen errorScreen = new NetworkErrorScreen(exception);
+
+				ScreenManager.AddScreen(errorScreen, ControllingPlayer);
+			}
+		}
+
+		enum SessionProperty { GameMode, SkillLevel, ScoreToWin }
+
+		enum GameMode { Practice, Timed, CaptureTheFlag }
+
+		enum SkillLevel { Beginner, Intermediate, Advanced }
+
+		/// <summary>
+		/// Event handler for when the asynchronous create network session
+		/// operation has completed.
+		/// </summary>
+		void CreateSessionOperationCompleted(object sender,
+					OperationCompletedEventArgs e)
+		{
+			try
+			{
+				// Use the result directly from the event args.
+				NetworkSession networkSession = e.Result as NetworkSession;
+				if (networkSession == null)
+					throw new InvalidOperationException("NetworkSession result was null or invalid.");
+
+				// Create a component that will manage the session we just created.
+				NetworkSessionComponent.Create(ScreenManager, networkSession);
+
+				// Go to the lobby screen. We pass null as the controlling player,
+				// because the lobby screen accepts input from all local players
+				// who are in the session, not just a single controlling player.
+				ScreenManager.AddScreen(new LobbyScreen(networkSession), null);
+			}
+			catch (Exception exception)
+			{
+				NetworkErrorScreen errorScreen = new NetworkErrorScreen(exception);
+
+				ScreenManager.AddScreen(errorScreen, ControllingPlayer);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the Find Sessions menu entry is selected.
+		/// </summary>
+		void FindSessionsMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			try
+			{
+				// Which local profiles should we include in this session?
+				IEnumerable<SignedInGamer> localGamers = NetworkSessionComponent.ChooseGamers(sessionType, ControllingPlayer.Value);
+
+				// Begin an asynchronous find network sessions operation.
+				var availableNetworkSessions = NetworkSession.FindAsync(
+					sessionType,
+					NetworkSessionComponent.MaxLocalGamers, null);
+
+				// Activate the network busy screen, which will display
+				// an animation until this operation has completed.
+				NetworkBusyScreen busyScreen = new NetworkBusyScreen(availableNetworkSessions);
+
+				busyScreen.OperationCompleted += FindSessionsOperationCompleted;
+
+				ScreenManager.AddScreen(busyScreen, ControllingPlayer);
+			}
+			catch (Exception exception)
+			{
+				NetworkErrorScreen errorScreen = new NetworkErrorScreen(exception);
+
+				ScreenManager.AddScreen(errorScreen, ControllingPlayer);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the asynchronous find network sessions
+		/// operation has completed.
+		/// </summary>
+		void FindSessionsOperationCompleted(object sender,
+					OperationCompletedEventArgs e)
+		{
+			GameScreen nextScreen;
+
+			try
+			{
+				// Use the result directly from the event args.
+				AvailableNetworkSessionCollection availableSessions = e.Result as AvailableNetworkSessionCollection;
+				if (availableSessions == null)
+					throw new InvalidOperationException("AvailableNetworkSessionCollection result was null or invalid.");
+
+				if (availableSessions.Count == 0)
+				{
+					// If we didn't find any sessions, display an error.
+					availableSessions.Dispose();
+
+					nextScreen = new MessageBoxScreen(Resources.NoSessionsFound, false);
+				}
+				else
+				{
+					// If we did find some sessions, proceed to the JoinSessionScreen.
+					nextScreen = new JoinSessionScreen(availableSessions);
+				}
+			}
+			catch (Exception exception)
+			{
+				nextScreen = new NetworkErrorScreen(exception);
+			}
+
+			ScreenManager.AddScreen(nextScreen, ControllingPlayer);
+		}
+	}
+}

+ 135 - 139
NetworkStateManagement/Networking/JoinSessionScreen.cs → NetworkStateManagement/Core/Networking/JoinSessionScreen.cs

@@ -1,139 +1,135 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// JoinSessionScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-using Microsoft.Xna.Framework.GamerServices;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// This menu screen displays a list of available network sessions,
-	/// and lets the user choose which one to join.
-	/// </summary>
-	class JoinSessionScreen : MenuScreen
-	{
-	#region Fields
-
-		const int MaxSearchResults = 8;
-		AvailableNetworkSessionCollection availableSessions;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructs a menu screen listing the available network sessions.
-		/// </summary>
-		public JoinSessionScreen (AvailableNetworkSessionCollection availableSessions)
-		: base(Resources.JoinSession)
-			{
-			this.availableSessions = availableSessions;
-
-			foreach (AvailableNetworkSession availableSession in availableSessions) {
-				// Create menu entries for each available session.
-				MenuEntry menuEntry = new AvailableSessionMenuEntry (availableSession);
-				menuEntry.Selected += AvailableSessionMenuEntrySelected;
-				MenuEntries.Add (menuEntry);
-
-				// Matchmaking can return up to 25 available sessions at a time, but
-				// we don't have room to fit that many on the screen. In a perfect
-				// world we should make the menu scroll if there are too many, but it
-				// is easier to just not bother displaying more than we have room for.
-				if (MenuEntries.Count >= MaxSearchResults)
-					break;
-			}
-
-			// Add the Back menu entry.
-			MenuEntry backMenuEntry = new MenuEntry (Resources.Back);
-			backMenuEntry.Selected += BackMenuEntrySelected;
-			MenuEntries.Add (backMenuEntry);
-		}
-
-
-	#endregion
-
-	#region Event Handlers
-
-
-		/// <summary>
-		/// Event handler for when an available session menu entry is selected.
-		/// </summary>
-		void AvailableSessionMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			// Which menu entry was selected?
-			AvailableSessionMenuEntry menuEntry = (AvailableSessionMenuEntry)sender;
-			AvailableNetworkSession availableSession = menuEntry.AvailableSession;
-
-			try {
-				// Begin an asynchronous join network session operation.
-				IAsyncResult asyncResult = NetworkSession.BeginJoin (availableSession, 
-								null, null);
-
-				// Activate the network busy screen, which will display
-				// an animation until this operation has completed.
-				NetworkBusyScreen busyScreen = new NetworkBusyScreen (asyncResult);
-
-				busyScreen.OperationCompleted += JoinSessionOperationCompleted;
-
-				ScreenManager.AddScreen (busyScreen, ControllingPlayer);
-			} catch (Exception exception) {
-				NetworkErrorScreen errorScreen = new NetworkErrorScreen (exception);
-
-				ScreenManager.AddScreen (errorScreen, ControllingPlayer);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the asynchronous join network session
-		/// operation has completed.
-		/// </summary>
-		void JoinSessionOperationCompleted (object sender, OperationCompletedEventArgs e)
-		{
-			try {
-				// End the asynchronous join network session operation.
-				NetworkSession networkSession = NetworkSession.EndJoin (e.AsyncResult);
-
-				// Create a component that will manage the session we just joined.
-				NetworkSessionComponent.Create (ScreenManager, networkSession);
-
-				// Go to the lobby screen. We pass null as the controlling player,
-				// because the lobby screen accepts input from all local players
-				// who are in the session, not just a single controlling player.
-				ScreenManager.AddScreen (new LobbyScreen (networkSession), null);
-
-				availableSessions.Dispose ();
-			} catch (Exception exception) {
-				NetworkErrorScreen errorScreen = new NetworkErrorScreen (exception);
-
-				ScreenManager.AddScreen (errorScreen, ControllingPlayer);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the Back menu entry is selected.
-		/// </summary>
-		void BackMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			availableSessions.Dispose ();
-
-			ExitScreen ();
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// JoinSessionScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+using Microsoft.Xna.Framework.GamerServices;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// This menu screen displays a list of available network sessions,
+	/// and lets the user choose which one to join.
+	/// </summary>
+	class JoinSessionScreen : MenuScreen
+	{
+
+		const int MaxSearchResults = 8;
+		AvailableNetworkSessionCollection availableSessions;
+
+
+
+
+		/// <summary>
+		/// Constructs a menu screen listing the available network sessions.
+		/// </summary>
+		public JoinSessionScreen(AvailableNetworkSessionCollection availableSessions)
+		: base(Resources.JoinSession)
+		{
+			this.availableSessions = availableSessions;
+
+			foreach (AvailableNetworkSession availableSession in availableSessions)
+			{
+				// Create menu entries for each available session.
+				MenuEntry menuEntry = new AvailableSessionMenuEntry(availableSession);
+				menuEntry.Selected += AvailableSessionMenuEntrySelected;
+				MenuEntries.Add(menuEntry);
+
+				// Matchmaking can return up to 25 available sessions at a time, but
+				// we don't have room to fit that many on the screen. In a perfect
+				// world we should make the menu scroll if there are too many, but it
+				// is easier to just not bother displaying more than we have room for.
+				if (MenuEntries.Count >= MaxSearchResults)
+					break;
+			}
+
+			// Add the Back menu entry.
+			MenuEntry backMenuEntry = new MenuEntry(Resources.Back);
+			backMenuEntry.Selected += BackMenuEntrySelected;
+			MenuEntries.Add(backMenuEntry);
+		}
+
+
+
+
+
+		/// <summary>
+		/// Event handler for when an available session menu entry is selected.
+		/// </summary>
+		void AvailableSessionMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			// Which menu entry was selected?
+			AvailableSessionMenuEntry menuEntry = (AvailableSessionMenuEntry)sender;
+			AvailableNetworkSession availableSession = menuEntry.AvailableSession;
+
+			try
+			{
+				// Begin an asynchronous join network session operation.
+				var networkSession = NetworkSession.JoinAsync(availableSession);
+
+				// Activate the network busy screen, which will display
+				// an animation until this operation has completed.
+				NetworkBusyScreen busyScreen = new NetworkBusyScreen(networkSession);
+
+				busyScreen.OperationCompleted += JoinSessionOperationCompleted;
+
+				ScreenManager.AddScreen(busyScreen, ControllingPlayer);
+			}
+			catch (Exception exception)
+			{
+				NetworkErrorScreen errorScreen = new NetworkErrorScreen(exception);
+
+				ScreenManager.AddScreen(errorScreen, ControllingPlayer);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the asynchronous join network session
+		/// operation has completed.
+		/// </summary>
+		void JoinSessionOperationCompleted(object sender, OperationCompletedEventArgs e)
+		{
+			try
+			{
+				// Use the result directly from the event args.
+				NetworkSession networkSession = e.Result as NetworkSession;
+				if (networkSession == null)
+					throw new InvalidOperationException("NetworkSession result was null or invalid.");
+
+				// Create a component that will manage the session we just joined.
+				NetworkSessionComponent.Create(ScreenManager, networkSession);
+
+				// Go to the lobby screen. We pass null as the controlling player,
+				// because the lobby screen accepts input from all local players
+				// who are in the session, not just a single controlling player.
+				ScreenManager.AddScreen(new LobbyScreen(networkSession), null);
+
+				availableSessions.Dispose();
+			}
+			catch (Exception exception)
+			{
+				NetworkErrorScreen errorScreen = new NetworkErrorScreen(exception);
+
+				ScreenManager.AddScreen(errorScreen, ControllingPlayer);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the Back menu entry is selected.
+		/// </summary>
+		void BackMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			availableSessions.Dispose();
+
+			ExitScreen();
+		}
+	}
+}

+ 289 - 277
NetworkStateManagement/Networking/LobbyScreen.cs → NetworkStateManagement/Core/Networking/LobbyScreen.cs

@@ -1,277 +1,289 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// LobbyScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Net;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// The lobby screen provides a place for gamers to congregate before starting
-	/// the actual gameplay. It displays a list of all the gamers in the session,
-	/// and indicates which ones are currently talking. Each gamer can press a button
-	/// to mark themselves as ready: gameplay will begin after everyone has done this.
-	/// </summary>
-	class LobbyScreen : GameScreen
-	{
-	#region Fields
-
-		NetworkSession networkSession;
-		Texture2D isReadyTexture;
-		Texture2D hasVoiceTexture;
-		Texture2D isTalkingTexture;
-		Texture2D voiceMutedTexture;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructs a new lobby screen.
-		/// </summary>
-		public LobbyScreen (NetworkSession networkSession)
-			{
-			this.networkSession = networkSession;
-
-			TransitionOnTime = TimeSpan.FromSeconds (0.5);
-			TransitionOffTime = TimeSpan.FromSeconds (0.5);
-			
-		}
-
-
-		/// <summary>
-		/// Loads graphics content used by the lobby screen.
-		/// </summary>
-		public override void LoadContent ()
-		{
-			ContentManager content = ScreenManager.Game.Content;
-
-			isReadyTexture = content.Load<Texture2D> ("chat_ready");
-			hasVoiceTexture = content.Load<Texture2D> ("chat_able");
-			isTalkingTexture = content.Load<Texture2D> ("chat_talking");
-			voiceMutedTexture = content.Load<Texture2D> ("chat_mute");
-		}
-
-
-	#endregion
-
-	#region Update
-
-
-		/// <summary>
-		/// Updates the lobby screen.
-		/// </summary>
-		public override void Update (GameTime gameTime, bool otherScreenHasFocus, 
-							bool coveredByOtherScreen)
-		{
-			base.Update (gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-			if (!IsExiting) {
-				if (networkSession.SessionState == NetworkSessionState.Playing) {
-					// Check if we should leave the lobby and begin gameplay.
-					// We pass null as the controlling player, because the networked
-					// gameplay screen accepts input from any local players who
-					// are in the session, not just a single controlling player.
-					LoadingScreen.Load (ScreenManager, true, null, 
-					new GameplayScreen (networkSession));
-				} else if (networkSession.IsHost && networkSession.IsEveryoneReady) {
-					// The host checks whether everyone has marked themselves
-					// as ready, and starts the game in response.
-					networkSession.StartGame ();
-				}
-			}
-		}
-
-
-		/// <summary>
-		/// Handles user input for all the local gamers in the session. Unlike most
-		/// screens, which use the InputState class to combine input data from all
-		/// gamepads, the lobby needs to individually mark specific players as ready,
-		/// so it loops over all the local gamers and reads their inputs individually.
-		/// </summary>
-		public override void HandleInput (InputState input)
-		{
-			foreach (LocalNetworkGamer gamer in networkSession.LocalGamers) {
-				PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex;
-
-				PlayerIndex unwantedOutput;
-
-				if (input.IsMenuSelect (playerIndex, out unwantedOutput)) {
-					HandleMenuSelect (gamer);
-				} else if (input.IsMenuCancel (playerIndex, out unwantedOutput)) {
-					HandleMenuCancel (gamer);
-				}
-			}
-		}
-
-
-		/// <summary>
-		/// Handle MenuSelect inputs by marking ourselves as ready.
-		/// </summary>
-		void HandleMenuSelect (LocalNetworkGamer gamer)
-		{
-			if (!gamer.IsReady) {
-				gamer.IsReady = true;
-			} else if (gamer.IsHost) {
-				// The host has an option to force starting the game, even if not
-				// everyone has marked themselves ready. If they press select twice
-				// in a row, the first time marks the host ready, then the second
-				// time we ask if they want to force start.
-				MessageBoxScreen messageBox = new MessageBoxScreen (
-						Resources.ConfirmForceStartGame);
-
-				messageBox.Accepted += ConfirmStartGameMessageBoxAccepted;
-
-				ScreenManager.AddScreen (messageBox, gamer.SignedInGamer.PlayerIndex);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the host selects ok on the "are you sure
-		/// you want to start even though not everyone is ready" message box.
-		/// </summary>
-		void ConfirmStartGameMessageBoxAccepted (object sender, PlayerIndexEventArgs e)
-		{
-			if (networkSession.SessionState == NetworkSessionState.Lobby) {
-				networkSession.StartGame ();
-			}
-		}
-
-
-		/// <summary>
-		/// Handle MenuCancel inputs by clearing our ready status, or if it is
-		/// already clear, prompting if the user wants to leave the session.
-		/// </summary>
-		void HandleMenuCancel (LocalNetworkGamer gamer)
-		{
-			if (gamer.IsReady) {
-				gamer.IsReady = false;
-			} else {
-				PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex;
-
-				NetworkSessionComponent.LeaveSession (ScreenManager, playerIndex);
-			}
-		}
-
-
-	#endregion
-
-	#region Draw
-
-
-		/// <summary>
-		/// Draws the lobby screen.
-		/// </summary>
-		public override void Draw (GameTime gameTime)
-		{
-			SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-			SpriteFont font = ScreenManager.Font;
-
-			Vector2 position = new Vector2 (100, 150);
-
-			// Make the lobby slide into place during transitions.
-			float transitionOffset = (float)Math.Pow (TransitionPosition, 2);
-
-			if (ScreenState == ScreenState.TransitionOn)
-				position.X -= transitionOffset * 256;
-			else
-				position.X += transitionOffset * 512;
-
-			spriteBatch.Begin ();
-
-			// Draw all the gamers in the session.
-			int gamerCount = 0;
-
-			foreach (NetworkGamer gamer in networkSession.AllGamers) {
-				DrawGamer (gamer, position);
-
-				// Advance to the next screen position, wrapping into two
-				// columns if there are more than 8 gamers in the session.
-				if (++gamerCount == 8) {
-					position.X += 433;
-					position.Y = 150;
-				} else
-					position.Y += ScreenManager.Font.LineSpacing;
-			}
-
-			// Draw the screen title.
-			string title = Resources.Lobby;
-
-			Vector2 titlePosition = new Vector2 (533, 80);
-			Vector2 titleOrigin = font.MeasureString (title) / 2;
-			Color titleColor = new Color (192, 192, 192) * TransitionAlpha;
-			float titleScale = 1.25f;
-
-			titlePosition.Y -= transitionOffset * 100;
-
-			spriteBatch.DrawString (font, title, titlePosition, titleColor, 0, 
-				titleOrigin, titleScale, SpriteEffects.None, 0);
-
-			spriteBatch.End ();
-		}
-
-
-		/// <summary>
-		/// Helper draws the gamertag and status icons for a single NetworkGamer.
-		/// </summary>
-		void DrawGamer (NetworkGamer gamer, Vector2 position)
-		{
-			SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-			SpriteFont font = ScreenManager.Font;
-
-			Vector2 iconWidth = new Vector2 (34, 0);
-			Vector2 iconOffset = new Vector2 (0, 12);
-
-			Vector2 iconPosition = position + iconOffset;
-
-			// Draw the "is ready" icon.
-			if (gamer.IsReady) {
-				spriteBatch.Draw (isReadyTexture, iconPosition, 
-				Color.Lime * TransitionAlpha);
-			}
-
-			iconPosition += iconWidth;
-
-			// Draw the "is muted", "is talking", or "has voice" icon.
-			if (gamer.IsMutedByLocalUser) {
-				spriteBatch.Draw (voiceMutedTexture, iconPosition, 
-				Color.Red * TransitionAlpha);
-			} else if (gamer.IsTalking) {
-				spriteBatch.Draw (isTalkingTexture, iconPosition, 
-				Color.Yellow * TransitionAlpha);
-			} else if (gamer.HasVoice) {
-				spriteBatch.Draw (hasVoiceTexture, iconPosition, 
-				Color.White * TransitionAlpha);
-			}
-
-			// Draw the gamertag, normally in white, but yellow for local players.
-			string text = gamer.Gamertag;
-
-			if (gamer.IsHost)
-				text += Resources.HostSuffix;
-
-			Color color = (gamer.IsLocal) ? Color.Yellow : Color.White;
-
-			spriteBatch.DrawString (font, text, position + iconWidth * 2, 
-				color * TransitionAlpha);
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// LobbyScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Net;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// The lobby screen provides a place for gamers to congregate before starting
+	/// the actual gameplay. It displays a list of all the gamers in the session,
+	/// and indicates which ones are currently talking. Each gamer can press a button
+	/// to mark themselves as ready: gameplay will begin after everyone has done this.
+	/// </summary>
+	class LobbyScreen : GameScreen
+	{
+
+		NetworkSession networkSession;
+		Texture2D isReadyTexture;
+		Texture2D hasVoiceTexture;
+		Texture2D isTalkingTexture;
+		Texture2D voiceMutedTexture;
+
+
+
+
+		/// <summary>
+		/// Constructs a new lobby screen.
+		/// </summary>
+		public LobbyScreen(NetworkSession networkSession)
+		{
+			this.networkSession = networkSession;
+
+			TransitionOnTime = TimeSpan.FromSeconds(0.5);
+			TransitionOffTime = TimeSpan.FromSeconds(0.5);
+
+		}
+
+
+		/// <summary>
+		/// Loads graphics content used by the lobby screen.
+		/// </summary>
+		public override void LoadContent()
+		{
+			ContentManager content = ScreenManager.Game.Content;
+
+			isReadyTexture = content.Load<Texture2D>("chat_ready");
+			hasVoiceTexture = content.Load<Texture2D>("chat_able");
+			isTalkingTexture = content.Load<Texture2D>("chat_talking");
+			voiceMutedTexture = content.Load<Texture2D>("chat_mute");
+		}
+
+
+
+
+
+		/// <summary>
+		/// Updates the lobby screen.
+		/// </summary>
+		public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+							bool coveredByOtherScreen)
+		{
+			base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+			if (!IsExiting)
+			{
+				if (networkSession.SessionState == NetworkSessionState.Playing)
+				{
+					// Check if we should leave the lobby and begin gameplay.
+					// We pass null as the controlling player, because the networked
+					// gameplay screen accepts input from any local players who
+					// are in the session, not just a single controlling player.
+					LoadingScreen.Load(ScreenManager, true, null,
+					new GameplayScreen(networkSession));
+				}
+				else if (networkSession.IsHost && networkSession.IsEveryoneReady)
+				{
+					// The host checks whether everyone has marked themselves
+					// as ready, and starts the game in response.
+					networkSession.StartGame();
+				}
+			}
+		}
+
+
+		/// <summary>
+		/// Handles user input for all the local gamers in the session. Unlike most
+		/// screens, which use the InputState class to combine input data from all
+		/// gamepads, the lobby needs to individually mark specific players as ready,
+		/// so it loops over all the local gamers and reads their inputs individually.
+		/// </summary>
+		public override void HandleInput(InputState input)
+		{
+			foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
+			{
+				PlayerIndex playerIndex = (PlayerIndex)gamer.SignedInGamer.PlayerIndex;
+
+				PlayerIndex unwantedOutput;
+
+				if (input.IsMenuSelect(playerIndex, out unwantedOutput))
+				{
+					HandleMenuSelect(gamer);
+				}
+				else if (input.IsMenuCancel(playerIndex, out unwantedOutput))
+				{
+					HandleMenuCancel(gamer);
+				}
+			}
+		}
+
+
+		/// <summary>
+		/// Handle MenuSelect inputs by marking ourselves as ready.
+		/// </summary>
+		void HandleMenuSelect(LocalNetworkGamer localGamer)
+		{
+			if (!localGamer.IsReady)
+			{
+				localGamer.IsReady = true;
+			}
+			else if (localGamer.IsHost)
+			{
+				// The host has an option to force starting the game, even if not
+				// everyone has marked themselves ready. If they press select twice
+				// in a row, the first time marks the host ready, then the second
+				// time we ask if they want to force start.
+				MessageBoxScreen messageBox = new MessageBoxScreen(
+						Resources.ConfirmForceStartGame);
+
+				messageBox.Accepted += ConfirmStartGameMessageBoxAccepted;
+
+				ScreenManager.AddScreen(messageBox, (PlayerIndex?)localGamer.SignedInGamer.PlayerIndex);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the host selects ok on the "are you sure
+		/// you want to start even though not everyone is ready" message box.
+		/// </summary>
+		void ConfirmStartGameMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+		{
+			if (networkSession.SessionState == NetworkSessionState.Lobby)
+			{
+				networkSession.StartGame();
+			}
+		}
+
+
+		/// <summary>
+		/// Handle MenuCancel inputs by clearing our ready status, or if it is
+		/// already clear, prompting if the user wants to leave the session.
+		/// </summary>
+		void HandleMenuCancel(LocalNetworkGamer localGamer)
+		{
+			if (localGamer.IsReady)
+			{
+				localGamer.IsReady = false;
+			}
+			else
+			{
+				PlayerIndex playerIndex = (PlayerIndex)localGamer.SignedInGamer.PlayerIndex;
+
+				NetworkSessionComponent.LeaveSession(ScreenManager, playerIndex);
+			}
+		}
+
+
+
+
+
+		/// <summary>
+		/// Draws the lobby screen.
+		/// </summary>
+		public override void Draw(GameTime gameTime)
+		{
+			SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+			SpriteFont font = ScreenManager.Font;
+
+			Vector2 position = new Vector2(100, 150);
+
+			// Make the lobby slide into place during transitions.
+			float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+			if (ScreenState == ScreenState.TransitionOn)
+				position.X -= transitionOffset * 256;
+			else
+				position.X += transitionOffset * 512;
+
+			spriteBatch.Begin();
+
+			// Draw all the gamers in the session.
+			int gamerCount = 0;
+
+			foreach (NetworkGamer gamer in networkSession.AllGamers)
+			{
+				DrawGamer(gamer, position);
+
+				// Advance to the next screen position, wrapping into two
+				// columns if there are more than 8 gamers in the session.
+				if (++gamerCount == 8)
+				{
+					position.X += 433;
+					position.Y = 150;
+				}
+				else
+					position.Y += ScreenManager.Font.LineSpacing;
+			}
+
+			// Draw the screen title.
+			string title = Resources.Lobby;
+
+			Vector2 titlePosition = new Vector2(533, 80);
+			Vector2 titleOrigin = font.MeasureString(title) / 2;
+			Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
+			float titleScale = 1.25f;
+
+			titlePosition.Y -= transitionOffset * 100;
+
+			spriteBatch.DrawString(font, title, titlePosition, titleColor, 0,
+				titleOrigin, titleScale, SpriteEffects.None, 0);
+
+			spriteBatch.End();
+		}
+
+
+		/// <summary>
+		/// Helper draws the gamertag and status icons for a single NetworkGamer.
+		/// </summary>
+		void DrawGamer(NetworkGamer gamer, Vector2 position)
+		{
+			SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+			SpriteFont font = ScreenManager.Font;
+
+			Vector2 iconWidth = new Vector2(34, 0);
+			Vector2 iconOffset = new Vector2(0, 12);
+
+			Vector2 iconPosition = position + iconOffset;
+
+			// Draw the "is ready" icon.
+			if (gamer.IsReady)
+			{
+				spriteBatch.Draw(isReadyTexture, iconPosition,
+				Color.Lime * TransitionAlpha);
+			}
+
+			iconPosition += iconWidth;
+
+			// Draw the "is muted", "is talking", or "has voice" icon.
+			if (gamer.IsMutedByLocalUser)
+			{
+				spriteBatch.Draw(voiceMutedTexture, iconPosition,
+				Color.Red * TransitionAlpha);
+			}
+			else if (gamer.IsTalking)
+			{
+				spriteBatch.Draw(isTalkingTexture, iconPosition,
+				Color.Yellow * TransitionAlpha);
+			}
+			else if (gamer.HasVoice)
+			{
+				spriteBatch.Draw(hasVoiceTexture, iconPosition,
+				Color.White * TransitionAlpha);
+			}
+
+			// Draw the gamertag, normally in white, but yellow for local players.
+			string text = gamer.Gamertag;
+
+			if (gamer.IsHost)
+				text += Resources.HostSuffix;
+
+			Color color = (gamer.IsLocal) ? Color.Yellow : Color.White;
+
+			spriteBatch.DrawString(font, text, position + iconWidth * 2,
+				color * TransitionAlpha);
+		}
+
+
+	}
+}

+ 154 - 169
NetworkStateManagement/Networking/NetworkBusyScreen.cs → NetworkStateManagement/Core/Networking/NetworkBusyScreen.cs

@@ -1,169 +1,154 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// NetworkBusyScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// When an asynchronous network operation (for instance searching for or joining a
-	/// session) is in progress, we want to display some sort of busy indicator to let
-	/// the user know the game hasn't just locked up. We also want to make sure they
-	/// can't pick some other menu option before the current operation has finished.
-	/// This screen takes care of both requirements in a single stroke. It monitors
-	/// the IAsyncResult returned by an asynchronous network call, displaying a busy
-	/// indicator for as long as the call is still in progress. When it notices the
-	/// IAsyncResult has completed, it raises an event to let the game know it should
-	/// proceed to the next step, after which the busy screen automatically goes away.
-	/// Because this screen is on top of all others for as long as the asynchronous
-	/// operation is in progress, it automatically takes over all user input,
-	/// preventing any other menu entries being selected until the operation completes.
-	/// </summary>
-	class NetworkBusyScreen : GameScreen
-	{
-	#region Fields
-
-		IAsyncResult asyncResult;
-		Texture2D gradientTexture;
-		Texture2D catTexture;
-
-	#endregion
-
-	#region Events
-
-		public event EventHandler<OperationCompletedEventArgs> OperationCompleted;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructs a network busy screen for the specified asynchronous operation.
-		/// </summary>
-		public NetworkBusyScreen (IAsyncResult asyncResult)
-			{
-			this.asyncResult = asyncResult;
-
-			IsPopup = true;
-
-			TransitionOnTime = TimeSpan.FromSeconds (0.1);
-			TransitionOffTime = TimeSpan.FromSeconds (0.2);
-		}
-
-
-		/// <summary>
-		/// Loads graphics content for this screen. This uses the shared ContentManager
-		/// provided by the Game class, so the content will remain loaded forever.
-		/// Whenever a subsequent NetworkBusyScreen tries to load this same content,
-		/// it will just get back another reference to the already loaded data.
-		/// </summary>
-		public override void LoadContent ()
-		{
-			ContentManager content = ScreenManager.Game.Content;
-
-			gradientTexture = content.Load<Texture2D> ("gradient");
-			catTexture = content.Load<Texture2D> ("cat");
-		}
-
-
-	#endregion
-
-	#region Update and Draw
-
-
-		/// <summary>
-		/// Updates the NetworkBusyScreen.
-		/// </summary>
-		public override void Update (GameTime gameTime, bool otherScreenHasFocus, 
-							bool coveredByOtherScreen)
-		{
-			base.Update (gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-			// Has our asynchronous operation completed?
-			if ((asyncResult != null) && asyncResult.IsCompleted) {
-				// If so, raise the OperationCompleted event.
-				if (OperationCompleted != null) {
-					OperationCompleted (this, 
-					new OperationCompletedEventArgs (asyncResult));
-				}
-
-				ExitScreen ();
-
-				asyncResult = null;
-			}
-		}
-
-
-		/// <summary>
-		/// Draws the NetworkBusyScreen.
-		/// </summary>
-		public override void Draw (GameTime gameTime)
-		{
-			SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-			SpriteFont font = ScreenManager.Font;
-
-			string message = Resources.NetworkBusy;
-
-			const int hPad = 32 ; 
-			const int vPad = 16 ; 
-
-			// Center the message text in the viewport.
-			Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-			Vector2 viewportSize = new Vector2 (viewport.Width, viewport.Height);
-			Vector2 textSize = font.MeasureString (message);
-
-			// Add enough room to spin a cat.
-			Vector2 catSize = new Vector2 (catTexture.Width);
-
-			textSize.X = Math.Max (textSize.X, catSize.X);
-			textSize.Y += catSize.Y + vPad;
-
-			Vector2 textPosition = (viewportSize - textSize) / 2;
-
-			// The background includes a border somewhat larger than the text itself.
-			Rectangle backgroundRectangle = new Rectangle ((int)textPosition.X - hPad,
-							(int)textPosition.Y - vPad,
-							(int)textSize.X + hPad * 2,
-							(int)textSize.Y + vPad * 2);
-
-			// Fade the popup alpha during transitions.
-			Color color = Color.White * TransitionAlpha;
-
-			spriteBatch.Begin ();
-
-			// Draw the background rectangle.
-			spriteBatch.Draw (gradientTexture, backgroundRectangle, color);
-
-			// Draw the message box text.
-			spriteBatch.DrawString (font, message, textPosition, color);
-
-			// Draw the spinning cat progress indicator.
-			float catRotation = (float)gameTime.TotalGameTime.TotalSeconds * 3;
-
-			Vector2 catPosition = new Vector2 (textPosition.X + textSize.X / 2,
-						textPosition.Y + textSize.Y - 
-								catSize.Y / 2);
-
-			spriteBatch.Draw (catTexture, catPosition, null, color, catRotation, 
-				catSize / 2, 1, SpriteEffects.None, 0);
-
-			spriteBatch.End ();
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// NetworkBusyScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// When an asynchronous network operation (for instance searching for or joining a
+	/// session) is in progress, we want to display some sort of busy indicator to let
+	/// the user know the game hasn't just locked up. We also want to make sure they
+	/// can't pick some other menu option before the current operation has finished.
+	/// This screen takes care of both requirements in a single stroke. It monitors
+	/// the IAsyncResult returned by an asynchronous network call, displaying a busy
+	/// indicator for as long as the call is still in progress. When it notices the
+	/// IAsyncResult has completed, it raises an event to let the game know it should
+	/// proceed to the next step, after which the busy screen automatically goes away.
+	/// Because this screen is on top of all others for as long as the asynchronous
+	/// operation is in progress, it automatically takes over all user input,
+	/// preventing any other menu entries being selected until the operation completes.
+	/// </summary>
+	class NetworkBusyScreen : GameScreen
+	{
+
+		IAsyncResult asyncResult;
+		Texture2D gradientTexture;
+		Texture2D catTexture;
+
+		public event EventHandler<OperationCompletedEventArgs> OperationCompleted;
+
+		/// <summary>
+		/// Constructs a network busy screen for the specified asynchronous operation.
+		/// </summary>
+		public NetworkBusyScreen(IAsyncResult asyncResult)
+		{
+			this.asyncResult = asyncResult;
+
+			IsPopup = true;
+
+			TransitionOnTime = TimeSpan.FromSeconds(0.1);
+			TransitionOffTime = TimeSpan.FromSeconds(0.2);
+		}
+
+
+		/// <summary>
+		/// Loads graphics content for this screen. This uses the shared ContentManager
+		/// provided by the Game class, so the content will remain loaded forever.
+		/// Whenever a subsequent NetworkBusyScreen tries to load this same content,
+		/// it will just get back another reference to the already loaded data.
+		/// </summary>
+		public override void LoadContent()
+		{
+			ContentManager content = ScreenManager.Game.Content;
+
+			gradientTexture = content.Load<Texture2D>("gradient");
+			catTexture = content.Load<Texture2D>("cat");
+		}
+
+
+
+
+
+		/// <summary>
+		/// Updates the NetworkBusyScreen.
+		/// </summary>
+		public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+							bool coveredByOtherScreen)
+		{
+			base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+			// Has our asynchronous operation completed?
+			if ((asyncResult != null) && asyncResult.IsCompleted)
+			{
+				// If so, raise the OperationCompleted event.
+				if (OperationCompleted != null)
+				{
+					OperationCompleted(this,
+					new OperationCompletedEventArgs(asyncResult));
+				}
+
+				ExitScreen();
+
+				asyncResult = null;
+			}
+		}
+
+
+		/// <summary>
+		/// Draws the NetworkBusyScreen.
+		/// </summary>
+		public override void Draw(GameTime gameTime)
+		{
+			SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+			SpriteFont font = ScreenManager.Font;
+
+			string message = Resources.NetworkBusy;
+
+			const int hPad = 32;
+			const int vPad = 16;
+
+			// Center the message text in the viewport.
+			Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+			Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+			Vector2 textSize = font.MeasureString(message);
+
+			// Add enough room to spin a cat.
+			Vector2 catSize = new Vector2(catTexture.Width);
+
+			textSize.X = Math.Max(textSize.X, catSize.X);
+			textSize.Y += catSize.Y + vPad;
+
+			Vector2 textPosition = (viewportSize - textSize) / 2;
+
+			// The background includes a border somewhat larger than the text itself.
+			Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
+							(int)textPosition.Y - vPad,
+							(int)textSize.X + hPad * 2,
+							(int)textSize.Y + vPad * 2);
+
+			// Fade the popup alpha during transitions.
+			Color color = Color.White * TransitionAlpha;
+
+			spriteBatch.Begin();
+
+			// Draw the background rectangle.
+			spriteBatch.Draw(gradientTexture, backgroundRectangle, color);
+
+			// Draw the message box text.
+			spriteBatch.DrawString(font, message, textPosition, color);
+
+			// Draw the spinning cat progress indicator.
+			float catRotation = (float)gameTime.TotalGameTime.TotalSeconds * 3;
+
+			Vector2 catPosition = new Vector2(textPosition.X + textSize.X / 2,
+						textPosition.Y + textSize.Y -
+								catSize.Y / 2);
+
+			spriteBatch.Draw(catTexture, catPosition, null, color, catRotation,
+				catSize / 2, 1, SpriteEffects.None, 0);
+
+			spriteBatch.End();
+		}
+
+
+	}
+}

+ 85 - 89
NetworkStateManagement/Networking/NetworkErrorScreen.cs → NetworkStateManagement/Core/Networking/NetworkErrorScreen.cs

@@ -1,89 +1,85 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// NetworkErrorScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Diagnostics;
-using Microsoft.Xna.Framework.GamerServices;
-using Microsoft.Xna.Framework.Net;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Specialized message box subclass, used to display network error messages.
-    /// </summary>
-    class NetworkErrorScreen : MessageBoxScreen
-    {
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs an error message box from the specified exception.
-        /// </summary>
-        public NetworkErrorScreen(Exception exception)
-            : base(GetErrorMessage(exception), false)
-        { }
-
-
-        /// <summary>
-        /// Converts a network exception into a user friendly error message.
-        /// </summary>
-        static string GetErrorMessage(Exception exception)
-        {
-            Debug.WriteLine("Network operation threw " + exception);
-
-            // Is this a GamerPrivilegeException?
-            if (exception is GamerPrivilegeException)
-            {
-                if (Guide.IsTrialMode)
-                    return Resources.ErrorTrialMode;
-                else
-                    return Resources.ErrorGamerPrivilege;
-            }
-
-            // Is it a NetworkSessionJoinException?
-            NetworkSessionJoinException joinException = exception as
-                                                            NetworkSessionJoinException;
-
-            if (joinException != null)
-            {
-                switch (joinException.JoinError)
-                {
-                    case NetworkSessionJoinError.SessionFull:
-                        return Resources.ErrorSessionFull;
-
-                    case NetworkSessionJoinError.SessionNotFound:
-                        return Resources.ErrorSessionNotFound;
-
-                    case NetworkSessionJoinError.SessionNotJoinable:
-                        return Resources.ErrorSessionNotJoinable;
-                }
-            }
-
-            // Is this a NetworkNotAvailableException?
-            if (exception is NetworkNotAvailableException)
-            {
-                return Resources.ErrorNetworkNotAvailable;
-            }
-
-            // Is this a NetworkException?
-            if (exception is NetworkException)
-            {
-                return Resources.ErrorNetwork;
-            }
-
-            // Otherwise just a generic error message.
-            return Resources.ErrorUnknown;
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// NetworkErrorScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Diagnostics;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Net;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Specialized message box subclass, used to display network error messages.
+    /// </summary>
+    class NetworkErrorScreen : MessageBoxScreen
+    {
+
+
+        /// <summary>
+        /// Constructs an error message box from the specified exception.
+        /// </summary>
+        public NetworkErrorScreen(Exception exception)
+            : base(GetErrorMessage(exception), false)
+        { }
+
+
+        /// <summary>
+        /// Converts a network exception into a user friendly error message.
+        /// </summary>
+        static string GetErrorMessage(Exception exception)
+        {
+            Debug.WriteLine("Network operation threw " + exception);
+
+            // Is this a GamerPrivilegeException?
+            if (exception is GamerPrivilegeException)
+            {
+                if (Guide.IsTrialMode)
+                    return Resources.ErrorTrialMode;
+                else
+                    return Resources.ErrorGamerPrivilege;
+            }
+
+            // Is it a NetworkSessionJoinException?
+            NetworkSessionJoinException joinException = exception as
+                                                            NetworkSessionJoinException;
+
+            if (joinException != null)
+            {
+                switch (joinException.JoinError)
+                {
+                    case NetworkSessionJoinError.SessionFull:
+                        return Resources.ErrorSessionFull;
+
+                    case NetworkSessionJoinError.SessionNotFound:
+                        return Resources.ErrorSessionNotFound;
+
+                    case NetworkSessionJoinError.SessionNotJoinable:
+                        return Resources.ErrorSessionNotJoinable;
+                }
+            }
+
+            // TODO: Check if the compatibility layer supports NetworkNotAvailableException
+            // For now, use generic network error handling
+            // Is this a NetworkNotAvailableException?
+            // if (exception is NetworkNotAvailableException)
+            // {
+            //     return Resources.ErrorNetworkNotAvailable;
+            // }
+
+            // Is this a NetworkException?
+            if (exception is NetworkException)
+            {
+                return Resources.ErrorNetwork;
+            }
+
+            // Otherwise just a generic error message.
+            return Resources.ErrorUnknown;
+        }
+
+
+    }
+}

+ 495 - 481
NetworkStateManagement/Networking/NetworkSessionComponent.cs → NetworkStateManagement/Core/Networking/NetworkSessionComponent.cs

@@ -1,481 +1,495 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// NetworkSessionComponent.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Linq;
-using System.Diagnostics;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-using Microsoft.Xna.Framework.GamerServices;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// Component in charge of owning and updating the current NetworkSession object.
-	/// This is responsible for calling NetworkSession.Update at regular intervals,
-	/// and also exposes the NetworkSession as a game service which can easily be
-	/// looked up by any other code that needs to access it.
-	/// </summary>
-	class NetworkSessionComponent : GameComponent
-	{
-	#region Fields
-
-		public const int MaxGamers = 16;
-		public const int MaxLocalGamers = 4;
-		ScreenManager screenManager;
-		NetworkSession networkSession;
-		IMessageDisplay messageDisplay;
-		bool notifyWhenPlayersJoinOrLeave;
-		string sessionEndMessage;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// The constructor is private: external callers should use the Create method.
-		/// </summary>
-		NetworkSessionComponent (ScreenManager screenManager, 
-				NetworkSession networkSession)
-		: base(screenManager.Game)
-			{
-			this.screenManager = screenManager;
-			this.networkSession = networkSession;
-
-			// Hook up our session event handlers.
-			networkSession.GamerJoined += GamerJoined;
-			networkSession.GamerLeft += GamerLeft;
-			networkSession.SessionEnded += NetworkSessionEnded;
-		}
-
-
-		/// <summary>
-		/// Creates a new NetworkSessionComponent.
-		/// </summary>
-		public static void Create (ScreenManager screenManager,
-				NetworkSession networkSession)
-		{
-			Game game = screenManager.Game;
-
-			// Register this network session as a service.
-			game.Services.AddService (typeof(NetworkSession), networkSession);
-
-			// Create a NetworkSessionComponent, and add it to the Game.
-			game.Components.Add (new NetworkSessionComponent (screenManager,
-							networkSession));
-		}
-
-
-		/// <summary>
-		/// Initializes the component.
-		/// </summary>
-		public override void Initialize ()
-		{
-			base.Initialize ();
-
-			// Look up the IMessageDisplay service, which will
-			// be used to report gamer join/leave notifications.
-			messageDisplay = (IMessageDisplay)Game.Services.GetService (
-							typeof(IMessageDisplay));
-
-			if (messageDisplay != null)
-				notifyWhenPlayersJoinOrLeave = true;
-		}
-
-
-		/// <summary>
-		/// Shuts down the component.
-		/// </summary>
-		protected override void Dispose (bool disposing)
-		{
-			if (disposing) {
-				// Remove the NetworkSessionComponent.
-				Game.Components.Remove (this);
-
-				// Remove the NetworkSession service.
-				Game.Services.RemoveService (typeof(NetworkSession));
-
-				// Dispose the NetworkSession.
-				if (networkSession != null) {
-					networkSession.Dispose ();
-					networkSession = null;
-				}
-			}
-
-			base.Dispose (disposing);
-		}
-
-
-	#endregion
-
-	#region Update
-
-
-		/// <summary>
-		/// Updates the network session.
-		/// </summary>
-		public override void Update (GameTime gameTime)
-		{
-			if (networkSession == null)
-				return;
-
-			try {
-				networkSession.Update ();
-
-				// Has the session ended?
-				if (networkSession.SessionState == NetworkSessionState.Ended) {
-					LeaveSession ();
-				}
-			} catch (Exception exception) {
-				// Handle any errors from the network session update.
-				Debug.WriteLine ("NetworkSession.Update threw " + exception);
-
-				sessionEndMessage = Resources.ErrorNetwork;
-
-				LeaveSession ();
-			}
-		}
-
-
-	#endregion
-
-	#region Event Handlers
-
-
-		/// <summary>
-		/// Event handler called when a gamer joins the session.
-		/// Displays a notification message.
-		/// </summary>
-		void GamerJoined (object sender, GamerJoinedEventArgs e)
-		{
-			if (notifyWhenPlayersJoinOrLeave) {
-				messageDisplay.ShowMessage (Resources.MessageGamerJoined, 
-					e.Gamer.Gamertag);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler called when a gamer leaves the session.
-		/// Displays a notification message.
-		/// </summary>
-		void GamerLeft (object sender, GamerLeftEventArgs e)
-		{
-			if (notifyWhenPlayersJoinOrLeave) {
-				messageDisplay.ShowMessage (Resources.MessageGamerLeft, 
-					e.Gamer.Gamertag);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler called when the network session ends.
-		/// Stores the end reason, so this can later be displayed to the user.
-		/// </summary>
-		void NetworkSessionEnded (object sender, NetworkSessionEndedEventArgs e)
-		{
-			switch (e.EndReason) {
-			case NetworkSessionEndReason.ClientSignedOut:
-				sessionEndMessage = null;
-				break;
-
-			case NetworkSessionEndReason.HostEndedSession:
-				sessionEndMessage = Resources.ErrorHostEndedSession;
-				break;
-
-			case NetworkSessionEndReason.RemovedByHost:
-				sessionEndMessage = Resources.ErrorRemovedByHost;
-				break;
-
-			case NetworkSessionEndReason.Disconnected:
-			default:
-				sessionEndMessage = Resources.ErrorDisconnected;
-				break;
-			}
-
-			notifyWhenPlayersJoinOrLeave = false;
-		}
-
-
-		/// <summary>
-		/// Event handler called when the system delivers an invite notification.
-		/// This can occur when the user accepts an invite that was sent to them by
-		/// a friend (pull mode), or if they choose the "Join Session In Progress"
-		/// option in their friends screen (push mode). The handler leaves the
-		/// current session (if any), then joins the session referred to by the
-		/// invite. It is not necessary to prompt the user before doing this, as
-		/// the Guide will already have taken care of the necessary confirmations
-		/// before the invite was delivered to you.
-		/// </summary>
-		public static void InviteAccepted (ScreenManager screenManager,
-					InviteAcceptedEventArgs e)
-		{
-			// If we are already in a network session, leave it now.
-			NetworkSessionComponent self = FindSessionComponent (screenManager.Game);
-
-			if (self != null)
-				self.Dispose ();
-
-			try			{
-				// Which local profiles should we include in this session?
-				IEnumerable<SignedInGamer> localGamers = 
-					ChooseGamers (NetworkSessionType.PlayerMatch, e.Gamer.PlayerIndex);
-
-				// Begin an asynchronous join-from-invite operation.
-				IAsyncResult asyncResult = NetworkSession.BeginJoinInvited (localGamers, 
-									null, null);
-
-				// Use the loading screen to replace whatever screens were previously
-				// active. This will completely reset the screen state, regardless of
-				// whether we were in the menus or playing a game when the invite was
-				// delivered. When the loading screen finishes, it will activate the
-				// network busy screen, which displays an animation as it waits for
-				// the join operation to complete.
-				NetworkBusyScreen busyScreen = new NetworkBusyScreen (asyncResult);
-
-				busyScreen.OperationCompleted += JoinInvitedOperationCompleted;
-
-				LoadingScreen.Load (screenManager, false, null, new BackgroundScreen (), 
-							busyScreen);
-			} catch (Exception exception) {
-				NetworkErrorScreen errorScreen = new NetworkErrorScreen (exception);
-
-				LoadingScreen.Load (screenManager, false, null, new BackgroundScreen (), 
-							new MainMenuScreen (), 
-							errorScreen);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the asynchronous join-from-invite
-		/// operation has completed.
-		/// </summary>
-		static void JoinInvitedOperationCompleted (object sender,
-						OperationCompletedEventArgs e)
-		{
-			ScreenManager screenManager = ((GameScreen)sender).ScreenManager;
-
-			try			{
-				// End the asynchronous join-from-invite operation.
-				NetworkSession networkSession = 
-					NetworkSession.EndJoinInvited (e.AsyncResult);
-
-				// Create a component that will manage the session we just created.
-				NetworkSessionComponent.Create (screenManager, networkSession);
-
-				// Go to the lobby screen.
-				screenManager.AddScreen (new LobbyScreen (networkSession), null);
-			} catch (Exception exception) {
-				screenManager.AddScreen (new MainMenuScreen (), null);
-				screenManager.AddScreen (new NetworkErrorScreen (exception), null);
-			}
-		}
-
-
-	#endregion
-
-	#region Methods
-
-
-		/// <summary>
-		/// Checks whether the specified session type is online.
-		/// Online sessions cannot be used by local profiles, or if
-		/// parental controls are enabled, or when running in trial mode.
-		/// </summary>
-		public static bool IsOnlineSessionType (NetworkSessionType sessionType)
-		{
-			switch (sessionType) {
-			case NetworkSessionType.Local:
-			case NetworkSessionType.SystemLink:
-				return false;
-
-			case NetworkSessionType.PlayerMatch:
-			//case NetworkSessionType.Ranked:
-				return true;
-
-			default:
-				throw new NotSupportedException ();
-			}
-		}
-
-
-		/// <summary>
-		/// Decides which local gamer profiles should be included in a network session.
-		/// This is passed the index of the primary gamer (the profile who selected the
-		/// relevant menu option, or who is responding to an invite). The primary gamer
-		/// will always be included in the session. Other gamers may also be added if
-		/// there are suitable profiles signed in. To control how many gamers can be
-		/// returned by this method, adjust the MaxLocalGamers constant.
-		/// </summary>
-		public static IEnumerable<SignedInGamer> ChooseGamers (
-							NetworkSessionType sessionType,
-							PlayerIndex playerIndex)
-		{
-			List<SignedInGamer> gamers = new List<SignedInGamer> ();
-
-			// Look up the primary gamer, and make sure they are signed in.
-			SignedInGamer primaryGamer = Gamer.SignedInGamers [playerIndex];
-
-			if (primaryGamer == null)
-				throw new GamerPrivilegeException ();
-
-			gamers.Add (primaryGamer);
-
-			// Check whether any other profiles should also be included.
-			foreach (SignedInGamer gamer in Gamer.SignedInGamers) {
-				// Never include more profiles than the MaxLocalGamers constant.
-				if (gamers.Count >= MaxLocalGamers)
-					break;
-
-				// Don't want two copies of the primary gamer!
-				if (gamer == primaryGamer)
-					continue;
-
-				// If this is an online session, make sure the profile is signed
-				// in to Live, and that it has the privilege for online gameplay.
-				if (IsOnlineSessionType (sessionType)) {
-					if (!gamer.IsSignedInToLive)
-						continue;
-
-					if (!gamer.Privileges.AllowOnlineSessions)
-						continue;
-				}
-
-				if (primaryGamer.IsGuest && !gamer.IsGuest && gamers [0] == primaryGamer) {
-					// Special case: if the primary gamer is a guest profile,
-					// we should insert some other non-guest at the start of the
-					// output list, because guests aren't allowed to host sessions.
-					gamers.Insert (0, gamer);
-				} else {
-					gamers.Add (gamer);
-				}
-			}
-
-			return gamers;
-		}
-
-
-		/// <summary>
-		/// Public method called when the user wants to leave the network session.
-		/// Displays a confirmation message box, then disposes the session, removes
-		/// the NetworkSessionComponent, and returns them to the main menu screen.
-		/// </summary>
-		public static void LeaveSession (ScreenManager screenManager,
-					PlayerIndex playerIndex)
-		{
-			NetworkSessionComponent self = FindSessionComponent (screenManager.Game);
-
-			if (self != null) {
-				// Display a message box to confirm the user really wants to leave.
-				string message;
-
-				if (self.networkSession.IsHost)
-					message = Resources.ConfirmEndSession;
-				else
-					message = Resources.ConfirmLeaveSession;
-
-				MessageBoxScreen confirmMessageBox = new MessageBoxScreen (message);
-
-				// Hook the messge box ok event to actually leave the session.
-				confirmMessageBox.Accepted += delegate
-		{
-			self.LeaveSession ();
-		};
-
-				screenManager.AddScreen (confirmMessageBox, playerIndex);
-			}
-		}
-
-
-		/// <summary>
-		/// Internal method for leaving the network session. This disposes the 
-		/// session, removes the NetworkSessionComponent, and returns the user
-		/// to the main menu screen.
-		/// </summary>
-		void LeaveSession ()
-		{
-			// Destroy this NetworkSessionComponent.
-			Dispose ();
-
-			// If we have a sessionEndMessage string explaining why the session has
-			// ended (maybe this was a network disconnect, or perhaps the host kicked
-			// us out?) create a message box to display this reason to the user.
-			MessageBoxScreen messageBox;
-
-			if (!string.IsNullOrEmpty (sessionEndMessage))
-				messageBox = new MessageBoxScreen (sessionEndMessage, false);
-			else
-				messageBox = null;
-
-			// At this point we want to return the user all the way to the main
-			// menu screen. But what if they just joined a session? In that case
-			// they went through this flow of screens:
-			//
-			//  - MainMenuScreen
-			//  - CreateOrFindSessionsScreen
-			//  - JoinSessionScreen (if joining, skipped if creating a new session)
-			//  - LobbyScreeen
-			//
-			// If we have these previous screens on the history stack, and the user
-			// backs out of the LobbyScreen, the right thing is just to pop off the
-			// intermediate screens, returning them to the existing MainMenuScreen
-			// instance without bothering to reload everything. But if the user is
-			// in gameplay, or has been in gameplay and then returned to the lobby,
-			// the screen stack will have been emptied.
-			//
-			// To do the right thing in both cases, we scan through the screen history
-			// stack looking for a MainMenuScreen. If we find one, we pop any
-			// subsequent screens so as to return back to it, while if we don't
-			// find it, we just reset everything via the LoadingScreen.
-
-			GameScreen[] screens = screenManager.GetScreens ();
-
-			// Look for the MainMenuScreen.
-			for (int i = 0; i < screens.Length; i++) {
-				if (screens [i] is MainMenuScreen) {
-					// If we found one, pop everything since then to return back to it.
-					for (int j = i + 1; j < screens.Length; j++)
-						screens [j].ExitScreen ();
-
-					// Display the why-did-the-session-end message box.
-					if (messageBox != null)
-						screenManager.AddScreen (messageBox, null);
-
-					return;
-				}
-			}
-
-			// If we didn't find an existing MainMenuScreen, reload everything.
-			// The why-did-the-session-end message box will be displayed after
-			// the loading screen has completed.
-			LoadingScreen.Load (screenManager, false, null, new BackgroundScreen (), 
-							new MainMenuScreen (), 
-							messageBox);
-		}
-
-
-		/// <summary>
-		/// Searches through the Game.Components collection to
-		/// find the NetworkSessionComponent (if any exists).
-		/// </summary>
-		static NetworkSessionComponent FindSessionComponent (Game game)
-		{
-			return game.Components.OfType<NetworkSessionComponent> ().FirstOrDefault ();
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// NetworkSessionComponent.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Linq;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+using Microsoft.Xna.Framework.GamerServices;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// Component in charge of owning and updating the current NetworkSession object.
+	/// This is responsible for calling NetworkSession.Update at regular intervals,
+	/// and also exposes the NetworkSession as a game service which can easily be
+	/// looked up by any other code that needs to access it.
+	/// </summary>
+	class NetworkSessionComponent : GameComponent
+	{
+
+		public const int MaxGamers = 16;
+		public const int MaxLocalGamers = 4;
+		ScreenManager screenManager;
+		NetworkSession networkSession;
+		IMessageDisplay messageDisplay;
+		bool notifyWhenPlayersJoinOrLeave;
+		string sessionEndMessage;
+
+
+
+
+		/// <summary>
+		/// The constructor is private: external callers should use the Create method.
+		/// </summary>
+		NetworkSessionComponent(ScreenManager screenManager,
+				NetworkSession networkSession)
+		: base(screenManager.Game)
+		{
+			this.screenManager = screenManager;
+			this.networkSession = networkSession;
+
+			// Hook up our session event handlers.
+			networkSession.GamerJoined += GamerJoined;
+			networkSession.GamerLeft += GamerLeft;
+			networkSession.SessionEnded += NetworkSessionEnded;
+		}
+
+
+		/// <summary>
+		/// Creates a new NetworkSessionComponent.
+		/// </summary>
+		public static void Create(ScreenManager screenManager,
+				NetworkSession networkSession)
+		{
+			Game game = screenManager.Game;
+
+			// Register this network session as a service.
+			game.Services.AddService(typeof(NetworkSession), networkSession);
+
+			// Create a NetworkSessionComponent, and add it to the Game.
+			game.Components.Add(new NetworkSessionComponent(screenManager,
+							networkSession));
+		}
+
+
+		/// <summary>
+		/// Initializes the component.
+		/// </summary>
+		public override void Initialize()
+		{
+			base.Initialize();
+
+			// Look up the IMessageDisplay service, which will
+			// be used to report gamer join/leave notifications.
+			messageDisplay = (IMessageDisplay)Game.Services.GetService(
+							typeof(IMessageDisplay));
+
+			if (messageDisplay != null)
+				notifyWhenPlayersJoinOrLeave = true;
+		}
+
+
+		/// <summary>
+		/// Shuts down the component.
+		/// </summary>
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing)
+			{
+				// Remove the NetworkSessionComponent.
+				Game.Components.Remove(this);
+
+				// Remove the NetworkSession service.
+				Game.Services.RemoveService(typeof(NetworkSession));
+
+				// Dispose the NetworkSession.
+				if (networkSession != null)
+				{
+					networkSession.Dispose();
+					networkSession = null;
+				}
+			}
+
+			base.Dispose(disposing);
+		}
+
+
+
+
+
+		/// <summary>
+		/// Updates the network session.
+		/// </summary>
+		public override void Update(GameTime gameTime)
+		{
+			if (networkSession == null)
+				return;
+
+			try
+			{
+				networkSession.Update();
+
+				// Has the session ended?
+				if (networkSession.SessionState == NetworkSessionState.Ended)
+				{
+					LeaveSession();
+				}
+			}
+			catch (Exception exception)
+			{
+				// Handle any errors from the network session update.
+				Debug.WriteLine("NetworkSession.Update threw " + exception);
+
+				sessionEndMessage = Resources.ErrorNetwork;
+
+				LeaveSession();
+			}
+		}
+
+
+
+
+
+		/// <summary>
+		/// Event handler called when a gamer joins the session.
+		/// Displays a notification message.
+		/// </summary>
+		void GamerJoined(object sender, GamerJoinedEventArgs e)
+		{
+			if (notifyWhenPlayersJoinOrLeave)
+			{
+				messageDisplay.ShowMessage(Resources.MessageGamerJoined,
+					e.Gamer.Gamertag);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler called when a gamer leaves the session.
+		/// Displays a notification message.
+		/// </summary>
+		void GamerLeft(object sender, GamerLeftEventArgs e)
+		{
+			if (notifyWhenPlayersJoinOrLeave)
+			{
+				messageDisplay.ShowMessage(Resources.MessageGamerLeft,
+					e.Gamer.Gamertag);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler called when the network session ends.
+		/// Stores the end reason, so this can later be displayed to the user.
+		/// </summary>
+		void NetworkSessionEnded(object sender, NetworkSessionEndedEventArgs e)
+		{
+			switch (e.EndReason)
+			{
+				case NetworkSessionEndReason.ClientSignedOut:
+					sessionEndMessage = null;
+					break;
+
+				case NetworkSessionEndReason.HostEndedSession:
+					sessionEndMessage = Resources.ErrorHostEndedSession;
+					break;
+
+				// TODO: Check if the compatibility layer supports RemovedByHost
+				// case NetworkSessionEndReason.RemovedByHost:
+				//	sessionEndMessage = Resources.ErrorRemovedByHost;
+				//	break;
+
+				case NetworkSessionEndReason.Disconnected:
+				default:
+					sessionEndMessage = Resources.ErrorDisconnected;
+					break;
+			}
+
+			notifyWhenPlayersJoinOrLeave = false;
+		}
+
+
+		/// <summary>
+		/// Event handler called when the system delivers an invite notification.
+		/// This can occur when the user accepts an invite that was sent to them by
+		/// a friend (pull mode), or if they choose the "Join Session In Progress"
+		/// option in their friends screen (push mode). The handler leaves the
+		/// current session (if any), then joins the session referred to by the
+		/// invite. It is not necessary to prompt the user before doing this, as
+		/// the Guide will already have taken care of the necessary confirmations
+		/// before the invite was delivered to you.
+		/// </summary>
+		public static void InviteAccepted(ScreenManager screenManager,
+					InviteAcceptedEventArgs e)
+		{
+			// If we are already in a network session, leave it now.
+			NetworkSessionComponent self = FindSessionComponent(screenManager.Game);
+
+			if (self != null)
+				self.Dispose(true);
+
+			try
+			{
+				// Which local profiles should we include in this session?
+				PlayerIndex defaultPlayerIndex = PlayerIndex.One;
+				IEnumerable<SignedInGamer> localGamers =
+					ChooseGamers(NetworkSessionType.PlayerMatch, defaultPlayerIndex);
+
+				// Begin an asynchronous join-from-invite operation using the modern API.
+				var joinTask = NetworkSession.JoinInvitedAsync(
+					localGamers,
+					null);
+
+				// Use the loading screen to replace whatever screens were previously
+				// active. This will completely reset the screen state, regardless of
+				// whether we were in the menus or playing a game when the invite was
+				// delivered. When the loading screen finishes, it will activate the
+				// network busy screen, which displays an animation as it waits for
+				// the join operation to complete.
+				NetworkBusyScreen busyScreen = new NetworkBusyScreen(joinTask);
+
+				busyScreen.OperationCompleted += JoinInvitedOperationCompleted;
+
+				LoadingScreen.Load(screenManager, false, null, new BackgroundScreen(),
+							busyScreen);
+			}
+			catch (Exception exception)
+			{
+				NetworkErrorScreen errorScreen = new NetworkErrorScreen(exception);
+
+				LoadingScreen.Load(screenManager, false, null, new BackgroundScreen(),
+							new MainMenuScreen(),
+							errorScreen);
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the asynchronous join-from-invite
+		/// operation has completed.
+		/// </summary>
+		static void JoinInvitedOperationCompleted(object sender,
+						OperationCompletedEventArgs e)
+		{
+			ScreenManager screenManager = ((GameScreen)sender).ScreenManager;
+
+			try
+			{
+				// Use the result directly from the event args.
+				NetworkSession networkSession = e.Result as NetworkSession;
+				if (networkSession == null)
+					throw new InvalidOperationException("NetworkSession result was null or invalid.");
+
+				// Create a component that will manage the session we just created.
+				NetworkSessionComponent.Create(screenManager, networkSession);
+
+				// Go to the lobby screen.
+				screenManager.AddScreen(new LobbyScreen(networkSession), null);
+			}
+			catch (Exception exception)
+			{
+				screenManager.AddScreen(new MainMenuScreen(), null);
+				screenManager.AddScreen(new NetworkErrorScreen(exception), null);
+			}
+		}
+
+
+
+
+
+		/// <summary>
+		/// Checks whether the specified session type is online.
+		/// Online sessions cannot be used by local profiles, or if
+		/// parental controls are enabled, or when running in trial mode.
+		/// </summary>
+		public static bool IsOnlineSessionType(NetworkSessionType sessionType)
+		{
+			switch (sessionType)
+			{
+				case NetworkSessionType.Local:
+				case NetworkSessionType.SystemLink:
+					return false;
+
+				case NetworkSessionType.PlayerMatch:
+					//case NetworkSessionType.Ranked:
+					return true;
+
+				default:
+					throw new NotSupportedException();
+			}
+		}
+
+
+		/// <summary>
+		/// Decides which local gamer profiles should be included in a network session.
+		/// This is passed the index of the primary gamer (the profile who selected the
+		/// relevant menu option, or who is responding to an invite). The primary gamer
+		/// will always be included in the session. Other gamers may also be added if
+		/// there are suitable profiles signed in. To control how many gamers can be
+		/// returned by this method, adjust the MaxLocalGamers constant.
+		/// </summary>
+		public static IEnumerable<SignedInGamer> ChooseGamers(
+							NetworkSessionType sessionType,
+							PlayerIndex playerIndex)
+		{
+			List<SignedInGamer> gamers = new List<SignedInGamer>();
+
+			// Look up the primary gamer, and make sure they are signed in.
+			SignedInGamer primaryGamer = Gamer.SignedInGamers[(int)playerIndex];
+
+			if (primaryGamer == null)
+				throw new GamerPrivilegeException();
+
+			gamers.Add(primaryGamer);
+
+			// Check whether any other profiles should also be included.
+			foreach (SignedInGamer gamer in Gamer.SignedInGamers)
+			{
+				// Never include more profiles than the MaxLocalGamers constant.
+				if (gamers.Count >= MaxLocalGamers)
+					break;
+
+				// Don't want two copies of the primary gamer!
+				if (gamer == primaryGamer)
+					continue;
+
+				// If this is an online session, make sure the profile is signed
+				// in to Live, and that it has the privilege for online gameplay.
+				if (IsOnlineSessionType(sessionType))
+				{
+					if (!gamer.IsSignedInToLive)
+						continue;
+
+					// TODO: Check if the compatibility layer supports Privileges
+					// For now, assume online privileges are available if signed in to Live
+					// if (!gamer.Privileges.AllowOnlineSessions)
+					//	continue;
+				}
+
+				if (primaryGamer.IsGuest && !gamer.IsGuest && gamers[0] == primaryGamer)
+				{
+					// Special case: if the primary gamer is a guest profile,
+					// we should insert some other non-guest at the start of the
+					// output list, because guests aren't allowed to host sessions.
+					gamers.Insert(0, gamer);
+				}
+				else
+				{
+					gamers.Add(gamer);
+				}
+			}
+
+			return gamers;
+		}
+
+
+		/// <summary>
+		/// Public method called when the user wants to leave the network session.
+		/// Displays a confirmation message box, then disposes the session, removes
+		/// the NetworkSessionComponent, and returns them to the main menu screen.
+		/// </summary>
+		public static void LeaveSession(ScreenManager screenManager,
+					PlayerIndex playerIndex)
+		{
+			NetworkSessionComponent self = FindSessionComponent(screenManager.Game);
+
+			if (self != null)
+			{
+				// Display a message box to confirm the user really wants to leave.
+				string message;
+
+				if (self.networkSession.IsHost)
+					message = Resources.ConfirmEndSession;
+				else
+					message = Resources.ConfirmLeaveSession;
+
+				MessageBoxScreen confirmMessageBox = new MessageBoxScreen(message);
+
+				// Hook the messge box ok event to actually leave the session.
+				confirmMessageBox.Accepted += delegate
+		{
+			self.LeaveSession();
+		};
+
+				screenManager.AddScreen(confirmMessageBox, playerIndex);
+			}
+		}
+
+
+		/// <summary>
+		/// Internal method for leaving the network session. This disposes the 
+		/// session, removes the NetworkSessionComponent, and returns the user
+		/// to the main menu screen.
+		/// </summary>
+		void LeaveSession()
+		{
+			// Destroy this NetworkSessionComponent.
+			Dispose(true);
+
+			// If we have a sessionEndMessage string explaining why the session has
+			// ended (maybe this was a network disconnect, or perhaps the host kicked
+			// us out?) create a message box to display this reason to the user.
+			MessageBoxScreen messageBox;
+
+			if (!string.IsNullOrEmpty(sessionEndMessage))
+				messageBox = new MessageBoxScreen(sessionEndMessage, false);
+			else
+				messageBox = null;
+
+			// At this point we want to return the user all the way to the main
+			// menu screen. But what if they just joined a session? In that case
+			// they went through this flow of screens:
+			//
+			//  - MainMenuScreen
+			//  - CreateOrFindSessionsScreen
+			//  - JoinSessionScreen (if joining, skipped if creating a new session)
+			//  - LobbyScreeen
+			//
+			// If we have these previous screens on the history stack, and the user
+			// backs out of the LobbyScreen, the right thing is just to pop off the
+			// intermediate screens, returning them to the existing MainMenuScreen
+			// instance without bothering to reload everything. But if the user is
+			// in gameplay, or has been in gameplay and then returned to the lobby,
+			// the screen stack will have been emptied.
+			//
+			// To do the right thing in both cases, we scan through the screen history
+			// stack looking for a MainMenuScreen. If we find one, we pop any
+			// subsequent screens so as to return back to it, while if we don't
+			// find it, we just reset everything via the LoadingScreen.
+
+			GameScreen[] screens = screenManager.GetScreens();
+
+			// Look for the MainMenuScreen.
+			for (int i = 0; i < screens.Length; i++)
+			{
+				if (screens[i] is MainMenuScreen)
+				{
+					// If we found one, pop everything since then to return back to it.
+					for (int j = i + 1; j < screens.Length; j++)
+						screens[j].ExitScreen();
+
+					// Display the why-did-the-session-end message box.
+					if (messageBox != null)
+						screenManager.AddScreen(messageBox, null);
+
+					return;
+				}
+			}
+
+			// If we didn't find an existing MainMenuScreen, reload everything.
+			// The why-did-the-session-end message box will be displayed after
+			// the loading screen has completed.
+			LoadingScreen.Load(screenManager, false, null, new BackgroundScreen(),
+							new MainMenuScreen(),
+							messageBox);
+		}
+
+
+		/// <summary>
+		/// Searches through the Game.Components collection to
+		/// find the NetworkSessionComponent (if any exists).
+		/// </summary>
+		static NetworkSessionComponent FindSessionComponent(Game game)
+		{
+			return game.Components.OfType<NetworkSessionComponent>().FirstOrDefault();
+		}
+	}
+}

+ 32 - 53
NetworkStateManagement/Networking/OperationCompletedEventArgs.cs → NetworkStateManagement/Core/Networking/OperationCompletedEventArgs.cs

@@ -1,53 +1,32 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// OperationCompletedEventArgs.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Custom EventArgs class used by the NetworkBusyScreen.OperationCompleted event.
-    /// </summary>
-    class OperationCompletedEventArgs : EventArgs
-    {
-        #region Properties
-
-
-        /// <summary>
-        /// Gets or sets the IAsyncResult associated with
-        /// the network operation that has just completed.
-        /// </summary>
-        public IAsyncResult AsyncResult
-        {
-            get { return asyncResult; }
-            set { asyncResult = value; }
-        }
-
-        IAsyncResult asyncResult;
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new event arguments class.
-        /// </summary>
-        public OperationCompletedEventArgs(IAsyncResult asyncResult)
-        {
-            this.asyncResult = asyncResult;
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// OperationCompletedEventArgs.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Custom EventArgs class used by the NetworkBusyScreen.OperationCompleted event.
+    /// </summary>
+    class OperationCompletedEventArgs : EventArgs
+    {
+
+
+        /// <summary>
+        /// Gets or sets the result of the network operation that has just completed.
+        /// </summary>
+        public object Result { get; set; }
+
+        /// <summary>
+        /// Constructs a new event arguments class.
+        /// </summary>
+        public OperationCompletedEventArgs(object result)
+        {
+            this.Result = result;
+        }
+    }
+}

+ 177 - 187
NetworkStateManagement/Networking/ProfileSignInScreen.cs → NetworkStateManagement/Core/Networking/ProfileSignInScreen.cs

@@ -1,187 +1,177 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// ProfileSignInScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-using Microsoft.Xna.Framework.GamerServices;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// In order to play a networked game, you must have a player profile signed in.
-    /// If you want to play on Live, that has to be a Live profile. Rather than just
-    /// failing with an error message, it is nice if we can automatically bring up the
-    /// Guide screen when we detect that no suitable profiles are currently signed in,
-    /// so the user can easily correct the problem. This screen checks the sign in
-    /// state, and brings up the Guide user interface if there is a problem with it.
-    /// It then raises an event as soon as a valid profile has been signed in.
-    /// 
-    /// There are two scenarios for how this can work. If no good profile is signed in:
-    /// 
-    ///     - MainMenuScreen activates the ProfileSignInScreen
-    ///     - ProfileSignInScreen activates the Guide user interface
-    ///     - User signs in a profile
-    ///     - ProfileSignInScreen raises the ProfileSignedIn event
-    ///     - This advances to the CreateOrFindSessionScreen
-    /// 
-    /// Alternatively, there might already be a valid profile signed in. In this case:
-    /// 
-    ///     - MainMenuScreen activates the ProfileSignInScreen
-    ///     - ProfileSignInScreen notices everything is already good
-    ///     - ProfileSignInScreen raises the ProfileSignedIn event
-    ///     - This advances to the CreateOrFindSessionScreen
-    /// 
-    /// In this second case, the ProfileSignInScreen is only active for a single
-    /// Update, so the user just sees a transition directly from the MainMenuScreen
-    /// to the CreateOrFindSessionScreen.
-    /// </summary>
-    class ProfileSignInScreen : GameScreen
-    {
-        #region Fields
-
-        NetworkSessionType sessionType;
-        bool haveShownGuide;
-        bool haveShownMarketplace;
-
-        #endregion
-
-        #region Events
-
-        public event EventHandler<EventArgs> ProfileSignedIn;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new profile sign in screen.
-        /// </summary>
-        public ProfileSignInScreen(NetworkSessionType sessionType)
-        {
-            this.sessionType = sessionType;
-
-            IsPopup = true;
-        }
-
-
-        #endregion
-
-        #region Update
-
-
-        /// <summary>
-        /// Updates the profile sign in screen.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-            if (ValidProfileSignedIn())
-            {
-                // As soon as we detect a suitable profile is signed in,
-                // we raise the profile signed in event, then go away.
-                if (ProfileSignedIn != null)
-                    ProfileSignedIn(this, EventArgs.Empty);
-
-                ExitScreen();
-            }
-            else if (IsActive && !Guide.IsVisible)
-            {
-                // If we are in trial mode, and they want to play online, and a profile
-                // is signed in, take them to marketplace so they can purchase the game.
-                if ((Guide.IsTrialMode) &&
-                    (NetworkSessionComponent.IsOnlineSessionType(sessionType)) &&
-                    (Gamer.SignedInGamers[ControllingPlayer.Value] != null) &&
-                    (!haveShownMarketplace))
-                {
-                    ShowMarketplace();
-
-                    haveShownMarketplace = true;
-                }
-                else if (!haveShownGuide && !haveShownMarketplace)
-                {
-                    // No suitable profile is signed in, and we haven't already shown
-                    // the Guide. Let's show it now, so they can sign in a profile.
-                    Guide.ShowSignIn(1,
-                            NetworkSessionComponent.IsOnlineSessionType(sessionType));
-
-                    haveShownGuide = true;
-                }
-                else
-                {
-                    // Hmm. No suitable profile is signed in, but we already showed
-                    // the Guide, and the Guide isn't still visible. There is only
-                    // one thing that can explain this: they must have cancelled the
-                    // Guide without signing in a profile. We'd better just exit,
-                    // which will leave us on the same menu as before.
-                    ExitScreen();
-                }
-            }
-        }
-
-
-        /// <summary>
-        /// Helper checks whether a valid player profile is signed in.
-        /// </summary>
-        bool ValidProfileSignedIn()
-        {
-            // If there is no profile signed in, that is never good.
-            SignedInGamer gamer = Gamer.SignedInGamers[ControllingPlayer.Value];
-
-            if (gamer == null)
-                return false;
-
-            // If we want to play in a Live session, also make sure the profile is
-            // signed in to Live, and that it has the privilege for online gameplay.
-            if (NetworkSessionComponent.IsOnlineSessionType(sessionType))
-            {
-                if (!gamer.IsSignedInToLive)
-                    return false;
-
-                if (!gamer.Privileges.AllowOnlineSessions)
-                    return false;
-            }
-
-            // Okeydokey, this looks good.
-            return true;
-        }
-
-
-        /// <summary>
-        /// LIVE networking is not supported in trial mode. Rather than just giving
-        /// the user an error, this function asks if they want to purchase the full
-        /// game, then takes them to Marketplace where they can do that. Once the
-        /// Guide is active, the user can either make the purchase, or cancel it.
-        /// When the Guide closes, ProfileSignInScreen.Update will notice that
-        /// Guide.IsVisible has gone back to false, at which point it will check if
-        /// the game is still in trial mode, and either exit the screen or proceed
-        /// forward accordingly.
-        /// </summary>
-        void ShowMarketplace()
-        {
-            MessageBoxScreen confirmMarketplaceMessageBox =
-                                    new MessageBoxScreen(Resources.ConfirmMarketplace);
-
-            confirmMarketplaceMessageBox.Accepted += delegate
-            {
-                Guide.ShowMarketplace(ControllingPlayer.Value);
-            };
-
-            ScreenManager.AddScreen(confirmMarketplaceMessageBox, ControllingPlayer);
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// ProfileSignInScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+using Microsoft.Xna.Framework.GamerServices;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// In order to play a networked game, you must have a player profile signed in.
+    /// If you want to play on Live, that has to be a Live profile. Rather than just
+    /// failing with an error message, it is nice if we can automatically bring up the
+    /// Guide screen when we detect that no suitable profiles are currently signed in,
+    /// so the user can easily correct the problem. This screen checks the sign in
+    /// state, and brings up the Guide user interface if there is a problem with it.
+    /// It then raises an event as soon as a valid profile has been signed in.
+    /// 
+    /// There are two scenarios for how this can work. If no good profile is signed in:
+    /// 
+    ///     - MainMenuScreen activates the ProfileSignInScreen
+    ///     - ProfileSignInScreen activates the Guide user interface
+    ///     - User signs in a profile
+    ///     - ProfileSignInScreen raises the ProfileSignedIn event
+    ///     - This advances to the CreateOrFindSessionScreen
+    /// 
+    /// Alternatively, there might already be a valid profile signed in. In this case:
+    /// 
+    ///     - MainMenuScreen activates the ProfileSignInScreen
+    ///     - ProfileSignInScreen notices everything is already good
+    ///     - ProfileSignInScreen raises the ProfileSignedIn event
+    ///     - This advances to the CreateOrFindSessionScreen
+    /// 
+    /// In this second case, the ProfileSignInScreen is only active for a single
+    /// Update, so the user just sees a transition directly from the MainMenuScreen
+    /// to the CreateOrFindSessionScreen.
+    /// </summary>
+    class ProfileSignInScreen : GameScreen
+    {
+
+        NetworkSessionType sessionType;
+        bool haveShownGuide;
+        bool haveShownMarketplace;
+
+
+
+        public event EventHandler<EventArgs> ProfileSignedIn;
+
+
+
+
+        /// <summary>
+        /// Constructs a new profile sign in screen.
+        /// </summary>
+        public ProfileSignInScreen(NetworkSessionType sessionType)
+        {
+            this.sessionType = sessionType;
+
+            IsPopup = true;
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the profile sign in screen.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            if (ValidProfileSignedIn())
+            {
+                // As soon as we detect a suitable profile is signed in,
+                // we raise the profile signed in event, then go away.
+                if (ProfileSignedIn != null)
+                    ProfileSignedIn(this, EventArgs.Empty);
+
+                ExitScreen();
+            }
+            else if (IsActive && !Guide.IsVisible)
+            {
+                // If we are in trial mode, and they want to play online, and a profile
+                // is signed in, take them to marketplace so they can purchase the game.
+                if ((Guide.IsTrialMode) &&
+                    (NetworkSessionComponent.IsOnlineSessionType(sessionType)) &&
+                    (Gamer.SignedInGamers[(int)ControllingPlayer.Value] != null) &&
+                    (!haveShownMarketplace))
+                {
+                    ShowMarketplace();
+
+                    haveShownMarketplace = true;
+                }
+                else if (!haveShownGuide && !haveShownMarketplace)
+                {
+                    // No suitable profile is signed in, and we haven't already shown
+                    // the Guide. Let's show it now, so they can sign in a profile.
+                    Guide.ShowSignIn(1,
+                            NetworkSessionComponent.IsOnlineSessionType(sessionType));
+
+                    haveShownGuide = true;
+                }
+                else
+                {
+                    // Hmm. No suitable profile is signed in, but we already showed
+                    // the Guide, and the Guide isn't still visible. There is only
+                    // one thing that can explain this: they must have cancelled the
+                    // Guide without signing in a profile. We'd better just exit,
+                    // which will leave us on the same menu as before.
+                    ExitScreen();
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Helper checks whether a valid player profile is signed in.
+        /// </summary>
+        bool ValidProfileSignedIn()
+        {
+            // If there is no profile signed in, that is never good.
+            SignedInGamer gamer = Gamer.SignedInGamers[(int)ControllingPlayer.Value];
+
+            if (gamer == null)
+                return false;
+
+            // If we want to play in a Live session, also make sure the profile is
+            // signed in to Live, and that it has the privilege for online gameplay.
+            if (NetworkSessionComponent.IsOnlineSessionType(sessionType))
+            {
+                if (!gamer.IsSignedInToLive)
+                    return false;
+
+                // TODO: Check if the compatibility layer supports Privileges
+                // For now, assume online privileges are available if signed in to Live
+                // if (!gamer.Privileges.AllowOnlineSessions)
+                //     return false;
+            }
+
+            // Okeydokey, this looks good.
+            return true;
+        }
+
+
+        /// <summary>
+        /// LIVE networking is not supported in trial mode. Rather than just giving
+        /// the user an error, this function asks if they want to purchase the full
+        /// game, then takes them to Marketplace where they can do that. Once the
+        /// Guide is active, the user can either make the purchase, or cancel it.
+        /// When the Guide closes, ProfileSignInScreen.Update will notice that
+        /// Guide.IsVisible has gone back to false, at which point it will check if
+        /// the game is still in trial mode, and either exit the screen or proceed
+        /// forward accordingly.
+        /// </summary>
+        void ShowMarketplace()
+        {
+            MessageBoxScreen confirmMarketplaceMessageBox =
+                                    new MessageBoxScreen(Resources.ConfirmMarketplace);
+
+            confirmMarketplaceMessageBox.Accepted += delegate
+            {
+                Guide.ShowMarketplace(ControllingPlayer.Value);
+            };
+
+            ScreenManager.AddScreen(confirmMarketplaceMessageBox, ControllingPlayer);
+        }
+
+
+    }
+}

+ 433 - 433
NetworkStateManagement/Resources.Designer.cs → NetworkStateManagement/Core/Resources.Designer.cs

@@ -1,433 +1,433 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by a tool.
-//     Runtime Version:4.0.30319.1
-//
-//     Changes to this file may cause incorrect behavior and will be lost if
-//     the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace NetworkStateManagement {
-    using System;
-    
-    
-    /// <summary>
-    ///   A strongly-typed resource class, for looking up localized strings, etc.
-    /// </summary>
-    // This class was auto-generated by the StronglyTypedResourceBuilder
-    // class via a tool like ResGen or Visual Studio.
-    // To add or remove a member, edit your .ResX file then rerun ResGen
-    // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    internal class Resources {
-        
-        private static global::System.Resources.ResourceManager resourceMan;
-        
-        private static global::System.Globalization.CultureInfo resourceCulture;
-        
-        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-        internal Resources() {
-        }
-        
-        /// <summary>
-        ///   Returns the cached ResourceManager instance used by this class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Resources.ResourceManager ResourceManager {
-            get {
-                if (object.ReferenceEquals(resourceMan, null)) {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NetworkStateManagement.Resources", typeof(Resources).Assembly);
-                    resourceMan = temp;
-                }
-                return resourceMan;
-            }
-        }
-        
-        /// <summary>
-        ///   Overrides the current thread's CurrentUICulture property for all
-        ///   resource lookups using this strongly typed resource class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Globalization.CultureInfo Culture {
-            get {
-                return resourceCulture;
-            }
-            set {
-                resourceCulture = value;
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Back.
-        /// </summary>
-        internal static string Back {
-            get {
-                return ResourceManager.GetString("Back", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Are you sure you want to end this session?.
-        /// </summary>
-        internal static string ConfirmEndSession {
-            get {
-                return ResourceManager.GetString("ConfirmEndSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Are you sure you want to exit this sample?.
-        /// </summary>
-        internal static string ConfirmExitSample {
-            get {
-                return ResourceManager.GetString("ConfirmExitSample", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Are you sure you want to start the game,
-        ///even though not all players are ready?.
-        /// </summary>
-        internal static string ConfirmForceStartGame {
-            get {
-                return ResourceManager.GetString("ConfirmForceStartGame", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Are you sure you want to leave this session?.
-        /// </summary>
-        internal static string ConfirmLeaveSession {
-            get {
-                return ResourceManager.GetString("ConfirmLeaveSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Online gameplay is not available in trial mode.
-        ///Would you like to purchase this game?.
-        /// </summary>
-        internal static string ConfirmMarketplace {
-            get {
-                return ResourceManager.GetString("ConfirmMarketplace", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Are you sure you want to quit this game?.
-        /// </summary>
-        internal static string ConfirmQuitGame {
-            get {
-                return ResourceManager.GetString("ConfirmQuitGame", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Create Session.
-        /// </summary>
-        internal static string CreateSession {
-            get {
-                return ResourceManager.GetString("CreateSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to End Session.
-        /// </summary>
-        internal static string EndSession {
-            get {
-                return ResourceManager.GetString("EndSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Lost connection to the network session.
-        /// </summary>
-        internal static string ErrorDisconnected {
-            get {
-                return ResourceManager.GetString("ErrorDisconnected", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to You must sign in a suitable gamer profile
-        ///in order to access this functionality.
-        /// </summary>
-        internal static string ErrorGamerPrivilege {
-            get {
-                return ResourceManager.GetString("ErrorGamerPrivilege", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Host ended the session.
-        /// </summary>
-        internal static string ErrorHostEndedSession {
-            get {
-                return ResourceManager.GetString("ErrorHostEndedSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to There was an error while
-        ///accessing the network.
-        /// </summary>
-        internal static string ErrorNetwork {
-            get {
-                return ResourceManager.GetString("ErrorNetwork", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Networking is turned
-        ///off or not connected.
-        /// </summary>
-        internal static string ErrorNetworkNotAvailable {
-            get {
-                return ResourceManager.GetString("ErrorNetworkNotAvailable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Host kicked you out of the session.
-        /// </summary>
-        internal static string ErrorRemovedByHost {
-            get {
-                return ResourceManager.GetString("ErrorRemovedByHost", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to This session is already full.
-        /// </summary>
-        internal static string ErrorSessionFull {
-            get {
-                return ResourceManager.GetString("ErrorSessionFull", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Session not found. It may have ended,
-        ///or there may be no network connectivity
-        ///between the local machine and session host.
-        /// </summary>
-        internal static string ErrorSessionNotFound {
-            get {
-                return ResourceManager.GetString("ErrorSessionNotFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to You must wait for the host to return to
-        ///the lobby before you can join this session.
-        /// </summary>
-        internal static string ErrorSessionNotJoinable {
-            get {
-                return ResourceManager.GetString("ErrorSessionNotJoinable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to This functionality is not available in trial mode.
-        /// </summary>
-        internal static string ErrorTrialMode {
-            get {
-                return ResourceManager.GetString("ErrorTrialMode", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to An unknown error occurred.
-        /// </summary>
-        internal static string ErrorUnknown {
-            get {
-                return ResourceManager.GetString("ErrorUnknown", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Exit.
-        /// </summary>
-        internal static string Exit {
-            get {
-                return ResourceManager.GetString("Exit", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Find Sessions.
-        /// </summary>
-        internal static string FindSessions {
-            get {
-                return ResourceManager.GetString("FindSessions", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to  (host).
-        /// </summary>
-        internal static string HostSuffix {
-            get {
-                return ResourceManager.GetString("HostSuffix", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Join Session.
-        /// </summary>
-        internal static string JoinSession {
-            get {
-                return ResourceManager.GetString("JoinSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Leave Session.
-        /// </summary>
-        internal static string LeaveSession {
-            get {
-                return ResourceManager.GetString("LeaveSession", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Loading.
-        /// </summary>
-        internal static string Loading {
-            get {
-                return ResourceManager.GetString("Loading", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Lobby.
-        /// </summary>
-        internal static string Lobby {
-            get {
-                return ResourceManager.GetString("Lobby", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Main Menu.
-        /// </summary>
-        internal static string MainMenu {
-            get {
-                return ResourceManager.GetString("MainMenu", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to 
-        ///A button, Space, Enter = ok
-        ///B button, Esc = cancel.
-        /// </summary>
-        internal static string MessageBoxUsage {
-            get {
-                return ResourceManager.GetString("MessageBoxUsage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} joined.
-        /// </summary>
-        internal static string MessageGamerJoined {
-            get {
-                return ResourceManager.GetString("MessageGamerJoined", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} left.
-        /// </summary>
-        internal static string MessageGamerLeft {
-            get {
-                return ResourceManager.GetString("MessageGamerLeft", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Networking....
-        /// </summary>
-        internal static string NetworkBusy {
-            get {
-                return ResourceManager.GetString("NetworkBusy", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to No sessions found.
-        /// </summary>
-        internal static string NoSessionsFound {
-            get {
-                return ResourceManager.GetString("NoSessionsFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Paused.
-        /// </summary>
-        internal static string Paused {
-            get {
-                return ResourceManager.GetString("Paused", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to LIVE.
-        /// </summary>
-        internal static string PlayerMatch {
-            get {
-                return ResourceManager.GetString("PlayerMatch", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Quit Game.
-        /// </summary>
-        internal static string QuitGame {
-            get {
-                return ResourceManager.GetString("QuitGame", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Resume Game.
-        /// </summary>
-        internal static string ResumeGame {
-            get {
-                return ResourceManager.GetString("ResumeGame", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Return to Lobby.
-        /// </summary>
-        internal static string ReturnToLobby {
-            get {
-                return ResourceManager.GetString("ReturnToLobby", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Single Player.
-        /// </summary>
-        internal static string SinglePlayer {
-            get {
-                return ResourceManager.GetString("SinglePlayer", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to System Link.
-        /// </summary>
-        internal static string SystemLink {
-            get {
-                return ResourceManager.GetString("SystemLink", resourceCulture);
-            }
-        }
-    }
-}
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.1
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace NetworkStateManagement {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NetworkStateManagement.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Back.
+        /// </summary>
+        internal static string Back {
+            get {
+                return ResourceManager.GetString("Back", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to end this session?.
+        /// </summary>
+        internal static string ConfirmEndSession {
+            get {
+                return ResourceManager.GetString("ConfirmEndSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to exit this sample?.
+        /// </summary>
+        internal static string ConfirmExitSample {
+            get {
+                return ResourceManager.GetString("ConfirmExitSample", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to start the game,
+        ///even though not all players are ready?.
+        /// </summary>
+        internal static string ConfirmForceStartGame {
+            get {
+                return ResourceManager.GetString("ConfirmForceStartGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to leave this session?.
+        /// </summary>
+        internal static string ConfirmLeaveSession {
+            get {
+                return ResourceManager.GetString("ConfirmLeaveSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Online gameplay is not available in trial mode.
+        ///Would you like to purchase this game?.
+        /// </summary>
+        internal static string ConfirmMarketplace {
+            get {
+                return ResourceManager.GetString("ConfirmMarketplace", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to quit this game?.
+        /// </summary>
+        internal static string ConfirmQuitGame {
+            get {
+                return ResourceManager.GetString("ConfirmQuitGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Create Session.
+        /// </summary>
+        internal static string CreateSession {
+            get {
+                return ResourceManager.GetString("CreateSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to End Session.
+        /// </summary>
+        internal static string EndSession {
+            get {
+                return ResourceManager.GetString("EndSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Lost connection to the network session.
+        /// </summary>
+        internal static string ErrorDisconnected {
+            get {
+                return ResourceManager.GetString("ErrorDisconnected", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to You must sign in a suitable gamer profile
+        ///in order to access this functionality.
+        /// </summary>
+        internal static string ErrorGamerPrivilege {
+            get {
+                return ResourceManager.GetString("ErrorGamerPrivilege", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Host ended the session.
+        /// </summary>
+        internal static string ErrorHostEndedSession {
+            get {
+                return ResourceManager.GetString("ErrorHostEndedSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to There was an error while
+        ///accessing the network.
+        /// </summary>
+        internal static string ErrorNetwork {
+            get {
+                return ResourceManager.GetString("ErrorNetwork", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Networking is turned
+        ///off or not connected.
+        /// </summary>
+        internal static string ErrorNetworkNotAvailable {
+            get {
+                return ResourceManager.GetString("ErrorNetworkNotAvailable", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Host kicked you out of the session.
+        /// </summary>
+        internal static string ErrorRemovedByHost {
+            get {
+                return ResourceManager.GetString("ErrorRemovedByHost", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to This session is already full.
+        /// </summary>
+        internal static string ErrorSessionFull {
+            get {
+                return ResourceManager.GetString("ErrorSessionFull", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Session not found. It may have ended,
+        ///or there may be no network connectivity
+        ///between the local machine and session host.
+        /// </summary>
+        internal static string ErrorSessionNotFound {
+            get {
+                return ResourceManager.GetString("ErrorSessionNotFound", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to You must wait for the host to return to
+        ///the lobby before you can join this session.
+        /// </summary>
+        internal static string ErrorSessionNotJoinable {
+            get {
+                return ResourceManager.GetString("ErrorSessionNotJoinable", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to This functionality is not available in trial mode.
+        /// </summary>
+        internal static string ErrorTrialMode {
+            get {
+                return ResourceManager.GetString("ErrorTrialMode", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to An unknown error occurred.
+        /// </summary>
+        internal static string ErrorUnknown {
+            get {
+                return ResourceManager.GetString("ErrorUnknown", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Exit.
+        /// </summary>
+        internal static string Exit {
+            get {
+                return ResourceManager.GetString("Exit", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Find Sessions.
+        /// </summary>
+        internal static string FindSessions {
+            get {
+                return ResourceManager.GetString("FindSessions", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to  (host).
+        /// </summary>
+        internal static string HostSuffix {
+            get {
+                return ResourceManager.GetString("HostSuffix", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Join Session.
+        /// </summary>
+        internal static string JoinSession {
+            get {
+                return ResourceManager.GetString("JoinSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Leave Session.
+        /// </summary>
+        internal static string LeaveSession {
+            get {
+                return ResourceManager.GetString("LeaveSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Loading.
+        /// </summary>
+        internal static string Loading {
+            get {
+                return ResourceManager.GetString("Loading", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Lobby.
+        /// </summary>
+        internal static string Lobby {
+            get {
+                return ResourceManager.GetString("Lobby", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Main Menu.
+        /// </summary>
+        internal static string MainMenu {
+            get {
+                return ResourceManager.GetString("MainMenu", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 
+        ///A button, Space, Enter = ok
+        ///B button, Esc = cancel.
+        /// </summary>
+        internal static string MessageBoxUsage {
+            get {
+                return ResourceManager.GetString("MessageBoxUsage", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} joined.
+        /// </summary>
+        internal static string MessageGamerJoined {
+            get {
+                return ResourceManager.GetString("MessageGamerJoined", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} left.
+        /// </summary>
+        internal static string MessageGamerLeft {
+            get {
+                return ResourceManager.GetString("MessageGamerLeft", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Networking....
+        /// </summary>
+        internal static string NetworkBusy {
+            get {
+                return ResourceManager.GetString("NetworkBusy", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to No sessions found.
+        /// </summary>
+        internal static string NoSessionsFound {
+            get {
+                return ResourceManager.GetString("NoSessionsFound", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Paused.
+        /// </summary>
+        internal static string Paused {
+            get {
+                return ResourceManager.GetString("Paused", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to LIVE.
+        /// </summary>
+        internal static string PlayerMatch {
+            get {
+                return ResourceManager.GetString("PlayerMatch", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Quit Game.
+        /// </summary>
+        internal static string QuitGame {
+            get {
+                return ResourceManager.GetString("QuitGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Resume Game.
+        /// </summary>
+        internal static string ResumeGame {
+            get {
+                return ResourceManager.GetString("ResumeGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Return to Lobby.
+        /// </summary>
+        internal static string ReturnToLobby {
+            get {
+                return ResourceManager.GetString("ReturnToLobby", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Single Player.
+        /// </summary>
+        internal static string SinglePlayer {
+            get {
+                return ResourceManager.GetString("SinglePlayer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to System Link.
+        /// </summary>
+        internal static string SystemLink {
+            get {
+                return ResourceManager.GetString("SystemLink", resourceCulture);
+            }
+        }
+    }
+}

+ 0 - 0
NetworkStateManagement/Resources.resources → NetworkStateManagement/Core/Resources.resources


+ 249 - 249
NetworkStateManagement/Resources.resx → NetworkStateManagement/Core/Resources.resx

@@ -1,250 +1,250 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <data name="Back" xml:space="preserve">
-    <value>Back</value>
-  </data>
-  <data name="ConfirmEndSession" xml:space="preserve">
-    <value>Are you sure you want to end this session?</value>
-  </data>
-  <data name="ConfirmExitSample" xml:space="preserve">
-    <value>Are you sure you want to exit this sample?</value>
-  </data>
-  <data name="ConfirmForceStartGame" xml:space="preserve">
-    <value>Are you sure you want to start the game,
-even though not all players are ready?</value>
-  </data>
-  <data name="ConfirmLeaveSession" xml:space="preserve">
-    <value>Are you sure you want to leave this session?</value>
-  </data>
-  <data name="ConfirmMarketplace" xml:space="preserve">
-    <value>Online gameplay is not available in trial mode.
-Would you like to purchase this game?</value>
-  </data>
-  <data name="ConfirmQuitGame" xml:space="preserve">
-    <value>Are you sure you want to quit this game?</value>
-  </data>
-  <data name="CreateSession" xml:space="preserve">
-    <value>Create Session</value>
-  </data>
-  <data name="EndSession" xml:space="preserve">
-    <value>End Session</value>
-  </data>
-  <data name="ErrorDisconnected" xml:space="preserve">
-    <value>Lost connection to the network session</value>
-  </data>
-  <data name="ErrorGamerPrivilege" xml:space="preserve">
-    <value>You must sign in a suitable gamer profile
-in order to access this functionality</value>
-  </data>
-  <data name="ErrorHostEndedSession" xml:space="preserve">
-    <value>Host ended the session</value>
-  </data>
-  <data name="ErrorNetwork" xml:space="preserve">
-    <value>There was an error while
-accessing the network</value>
-  </data>
-  <data name="ErrorNetworkNotAvailable" xml:space="preserve">
-    <value>Networking is turned
-off or not connected</value>
-  </data>
-  <data name="ErrorRemovedByHost" xml:space="preserve">
-    <value>Host kicked you out of the session</value>
-  </data>
-  <data name="ErrorSessionFull" xml:space="preserve">
-    <value>This session is already full</value>
-  </data>
-  <data name="ErrorSessionNotFound" xml:space="preserve">
-    <value>Session not found. It may have ended,
-or there may be no network connectivity
-between the local machine and session host</value>
-  </data>
-  <data name="ErrorSessionNotJoinable" xml:space="preserve">
-    <value>You must wait for the host to return to
-the lobby before you can join this session</value>
-  </data>
-  <data name="ErrorTrialMode" xml:space="preserve">
-    <value>This functionality is not available in trial mode</value>
-  </data>
-  <data name="ErrorUnknown" xml:space="preserve">
-    <value>An unknown error occurred</value>
-  </data>
-  <data name="Exit" xml:space="preserve">
-    <value>Exit</value>
-  </data>
-  <data name="FindSessions" xml:space="preserve">
-    <value>Find Sessions</value>
-  </data>
-  <data name="HostSuffix" xml:space="preserve">
-    <value> (host)</value>
-  </data>
-  <data name="JoinSession" xml:space="preserve">
-    <value>Join Session</value>
-  </data>
-  <data name="LeaveSession" xml:space="preserve">
-    <value>Leave Session</value>
-  </data>
-  <data name="Loading" xml:space="preserve">
-    <value>Loading</value>
-  </data>
-  <data name="Lobby" xml:space="preserve">
-    <value>Lobby</value>
-  </data>
-  <data name="MainMenu" xml:space="preserve">
-    <value>Main Menu</value>
-  </data>
-  <data name="MessageBoxUsage" xml:space="preserve">
-    <value>
-A button, Space, Enter = ok
-B button, Esc = cancel</value>
-  </data>
-  <data name="MessageGamerJoined" xml:space="preserve">
-    <value>{0} joined</value>
-  </data>
-  <data name="MessageGamerLeft" xml:space="preserve">
-    <value>{0} left</value>
-  </data>
-  <data name="NetworkBusy" xml:space="preserve">
-    <value>Networking...</value>
-  </data>
-  <data name="NoSessionsFound" xml:space="preserve">
-    <value>No sessions found</value>
-  </data>
-  <data name="Paused" xml:space="preserve">
-    <value>Paused</value>
-  </data>
-  <data name="PlayerMatch" xml:space="preserve">
-    <value>LIVE</value>
-  </data>
-  <data name="QuitGame" xml:space="preserve">
-    <value>Quit Game</value>
-  </data>
-  <data name="ResumeGame" xml:space="preserve">
-    <value>Resume Game</value>
-  </data>
-  <data name="ReturnToLobby" xml:space="preserve">
-    <value>Return to Lobby</value>
-  </data>
-  <data name="SinglePlayer" xml:space="preserve">
-    <value>Single Player</value>
-  </data>
-  <data name="SystemLink" xml:space="preserve">
-    <value>System Link</value>
-  </data>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="Back" xml:space="preserve">
+    <value>Back</value>
+  </data>
+  <data name="ConfirmEndSession" xml:space="preserve">
+    <value>Are you sure you want to end this session?</value>
+  </data>
+  <data name="ConfirmExitSample" xml:space="preserve">
+    <value>Are you sure you want to exit this sample?</value>
+  </data>
+  <data name="ConfirmForceStartGame" xml:space="preserve">
+    <value>Are you sure you want to start the game,
+even though not all players are ready?</value>
+  </data>
+  <data name="ConfirmLeaveSession" xml:space="preserve">
+    <value>Are you sure you want to leave this session?</value>
+  </data>
+  <data name="ConfirmMarketplace" xml:space="preserve">
+    <value>Online gameplay is not available in trial mode.
+Would you like to purchase this game?</value>
+  </data>
+  <data name="ConfirmQuitGame" xml:space="preserve">
+    <value>Are you sure you want to quit this game?</value>
+  </data>
+  <data name="CreateSession" xml:space="preserve">
+    <value>Create Session</value>
+  </data>
+  <data name="EndSession" xml:space="preserve">
+    <value>End Session</value>
+  </data>
+  <data name="ErrorDisconnected" xml:space="preserve">
+    <value>Lost connection to the network session</value>
+  </data>
+  <data name="ErrorGamerPrivilege" xml:space="preserve">
+    <value>You must sign in a suitable gamer profile
+in order to access this functionality</value>
+  </data>
+  <data name="ErrorHostEndedSession" xml:space="preserve">
+    <value>Host ended the session</value>
+  </data>
+  <data name="ErrorNetwork" xml:space="preserve">
+    <value>There was an error while
+accessing the network</value>
+  </data>
+  <data name="ErrorNetworkNotAvailable" xml:space="preserve">
+    <value>Networking is turned
+off or not connected</value>
+  </data>
+  <data name="ErrorRemovedByHost" xml:space="preserve">
+    <value>Host kicked you out of the session</value>
+  </data>
+  <data name="ErrorSessionFull" xml:space="preserve">
+    <value>This session is already full</value>
+  </data>
+  <data name="ErrorSessionNotFound" xml:space="preserve">
+    <value>Session not found. It may have ended,
+or there may be no network connectivity
+between the local machine and session host</value>
+  </data>
+  <data name="ErrorSessionNotJoinable" xml:space="preserve">
+    <value>You must wait for the host to return to
+the lobby before you can join this session</value>
+  </data>
+  <data name="ErrorTrialMode" xml:space="preserve">
+    <value>This functionality is not available in trial mode</value>
+  </data>
+  <data name="ErrorUnknown" xml:space="preserve">
+    <value>An unknown error occurred</value>
+  </data>
+  <data name="Exit" xml:space="preserve">
+    <value>Exit</value>
+  </data>
+  <data name="FindSessions" xml:space="preserve">
+    <value>Find Sessions</value>
+  </data>
+  <data name="HostSuffix" xml:space="preserve">
+    <value> (host)</value>
+  </data>
+  <data name="JoinSession" xml:space="preserve">
+    <value>Join Session</value>
+  </data>
+  <data name="LeaveSession" xml:space="preserve">
+    <value>Leave Session</value>
+  </data>
+  <data name="Loading" xml:space="preserve">
+    <value>Loading</value>
+  </data>
+  <data name="Lobby" xml:space="preserve">
+    <value>Lobby</value>
+  </data>
+  <data name="MainMenu" xml:space="preserve">
+    <value>Main Menu</value>
+  </data>
+  <data name="MessageBoxUsage" xml:space="preserve">
+    <value>
+A button, Space, Enter = ok
+B button, Esc = cancel</value>
+  </data>
+  <data name="MessageGamerJoined" xml:space="preserve">
+    <value>{0} joined</value>
+  </data>
+  <data name="MessageGamerLeft" xml:space="preserve">
+    <value>{0} left</value>
+  </data>
+  <data name="NetworkBusy" xml:space="preserve">
+    <value>Networking...</value>
+  </data>
+  <data name="NoSessionsFound" xml:space="preserve">
+    <value>No sessions found</value>
+  </data>
+  <data name="Paused" xml:space="preserve">
+    <value>Paused</value>
+  </data>
+  <data name="PlayerMatch" xml:space="preserve">
+    <value>LIVE</value>
+  </data>
+  <data name="QuitGame" xml:space="preserve">
+    <value>Quit Game</value>
+  </data>
+  <data name="ResumeGame" xml:space="preserve">
+    <value>Resume Game</value>
+  </data>
+  <data name="ReturnToLobby" xml:space="preserve">
+    <value>Return to Lobby</value>
+  </data>
+  <data name="SinglePlayer" xml:space="preserve">
+    <value>Single Player</value>
+  </data>
+  <data name="SystemLink" xml:space="preserve">
+    <value>System Link</value>
+  </data>
 </root>

+ 353 - 335
NetworkStateManagement/ScreenManager/GameScreen.cs → NetworkStateManagement/Core/ScreenManager/GameScreen.cs

@@ -1,335 +1,353 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// GameScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Input.Touch;
-using System.IO;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// Enum describes the screen transition state.
-	/// </summary>
-	public enum ScreenState
-	{
-		TransitionOn,
-		Active,
-		TransitionOff,
-		Hidden,
-	}
-
-
-	/// <summary>
-	/// A screen is a single layer that has update and draw logic, and which
-	/// can be combined with other layers to build up a complex menu system.
-	/// For instance the main menu, the options menu, the "are you sure you
-	/// want to quit" message box, and the main game itself are all implemented
-	/// as screens.
-	/// </summary>
-	public abstract class GameScreen
-	{
-	#region Properties
-
-
-		/// <summary>
-		/// Normally when one screen is brought up over the top of another,
-		/// the first screen will transition off to make room for the new
-		/// one. This property indicates whether the screen is only a small
-		/// popup, in which case screens underneath it do not need to bother
-		/// transitioning off.
-		/// </summary>
-		public bool IsPopup {
-			get { return isPopup; }
-			protected set { isPopup = value; }
-		}
-
-		bool isPopup = false;
-
-
-		/// <summary>
-		/// Indicates how long the screen takes to
-		/// transition on when it is activated.
-		/// </summary>
-		public TimeSpan TransitionOnTime {
-			get { return transitionOnTime; }
-			protected set { transitionOnTime = value; }
-		}
-
-		TimeSpan transitionOnTime = TimeSpan.Zero;
-
-
-		/// <summary>
-		/// Indicates how long the screen takes to
-		/// transition off when it is deactivated.
-		/// </summary>
-		public TimeSpan TransitionOffTime {
-			get { return transitionOffTime; }
-			protected set { transitionOffTime = value; }
-		}
-
-		TimeSpan transitionOffTime = TimeSpan.Zero;
-
-
-		/// <summary>
-		/// Gets the current position of the screen transition, ranging
-		/// from zero (fully active, no transition) to one (transitioned
-		/// fully off to nothing).
-		/// </summary>
-		public float TransitionPosition {
-			get { return transitionPosition; }
-			protected set { transitionPosition = value; }
-		}
-
-		float transitionPosition = 1;
-
-
-		/// <summary>
-		/// Gets the current alpha of the screen transition, ranging
-		/// from 1 (fully active, no transition) to 0 (transitioned
-		/// fully off to nothing).
-		/// </summary>
-		public float TransitionAlpha {
-			get { return 1f - TransitionPosition; }
-		}
-
-
-		/// <summary>
-		/// Gets the current screen transition state.
-		/// </summary>
-		public ScreenState ScreenState {
-			get { return screenState; }
-			protected set { screenState = value; }
-		}
-
-		ScreenState screenState = ScreenState.TransitionOn;
-
-
-		/// <summary>
-		/// There are two possible reasons why a screen might be transitioning
-		/// off. It could be temporarily going away to make room for another
-		/// screen that is on top of it, or it could be going away for good.
-		/// This property indicates whether the screen is exiting for real:
-		/// if set, the screen will automatically remove itself as soon as the
-		/// transition finishes.
-		/// </summary>
-		public bool IsExiting {
-			get { return isExiting; }
-			protected internal set { isExiting = value; }
-		}
-
-		bool isExiting = false;
-
-
-		/// <summary>
-		/// Checks whether this screen is active and can respond to user input.
-		/// </summary>
-		public bool IsActive {
-			get {
-				return !otherScreenHasFocus && 
-			(screenState == ScreenState.TransitionOn || 
-			screenState == ScreenState.Active);
-			}
-		}
-
-		bool otherScreenHasFocus;
-
-
-		/// <summary>
-		/// Gets the manager that this screen belongs to.
-		/// </summary>
-		public ScreenManager ScreenManager {
-			get { return screenManager; }
-			internal set { screenManager = value; }
-		}
-
-		ScreenManager screenManager;
-
-
-		/// <summary>
-		/// Gets the index of the player who is currently controlling this screen,
-		/// or null if it is accepting input from any player. This is used to lock
-		/// the game to a specific player profile. The main menu responds to input
-		/// from any connected gamepad, but whichever player makes a selection from
-		/// this menu is given control over all subsequent screens, so other gamepads
-		/// are inactive until the controlling player returns to the main menu.
-		/// </summary>
-		public PlayerIndex? ControllingPlayer {
-			get { return controllingPlayer; }
-			internal set { controllingPlayer = value; }
-		}
-
-		PlayerIndex? controllingPlayer;
-
-
-		/// <summary>
-		/// Gets the gestures the screen is interested in. Screens should be as specific
-		/// as possible with gestures to increase the accuracy of the gesture engine.
-		/// For example, most menus only need Tap or perhaps Tap and VerticalDrag to operate.
-		/// These gestures are handled by the ScreenManager when screens change and
-		/// all gestures are placed in the InputState passed to the HandleInput method.
-		/// </summary>
-		public GestureType EnabledGestures {
-			get { return enabledGestures; }
-			protected set {
-				enabledGestures = value;
-
-				// the screen manager handles this during screen changes, but
-				// if this screen is active and the gesture types are changing,
-				// we have to update the TouchPanel ourself.
-				if (ScreenState == ScreenState.Active) {
-					TouchPanel.EnabledGestures = value;
-				}
-			}
-		}
-
-		GestureType enabledGestures = GestureType.None;
-
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Load graphics content for the screen.
-		/// </summary>
-		public virtual void LoadContent ()
-		{
-		}
-
-
-		/// <summary>
-		/// Unload content for the screen.
-		/// </summary>
-		public virtual void UnloadContent ()
-		{
-		}
-
-
-	#endregion
-
-	#region Update and Draw
-
-
-		/// <summary>
-		/// Allows the screen to run logic, such as updating the transition position.
-		/// Unlike HandleInput, this method is called regardless of whether the screen
-		/// is active, hidden, or in the middle of a transition.
-		/// </summary>
-		public virtual void Update (GameTime gameTime, bool otherScreenHasFocus, 
-						bool coveredByOtherScreen)
-		{
-			this.otherScreenHasFocus = otherScreenHasFocus;
-
-			if (isExiting) {
-				// If the screen is going away to die, it should transition off.
-				screenState = ScreenState.TransitionOff;
-
-				if (!UpdateTransition (gameTime, transitionOffTime, 1)) {
-					// When the transition finishes, remove the screen.
-					ScreenManager.RemoveScreen (this);
-				}
-			} else if (coveredByOtherScreen) {
-				// If the screen is covered by another, it should transition off.
-				if (UpdateTransition (gameTime, transitionOffTime, 1)) {
-					// Still busy transitioning.
-					screenState = ScreenState.TransitionOff;
-				} else {
-					// Transition finished!
-					screenState = ScreenState.Hidden;
-				}
-			} else {
-				// Otherwise the screen should transition on and become active.
-				if (UpdateTransition (gameTime, transitionOnTime, -1)) {
-					// Still busy transitioning.
-					screenState = ScreenState.TransitionOn;
-				} else {
-					// Transition finished!
-					screenState = ScreenState.Active;
-				}
-			}
-		}
-
-
-		/// <summary>
-		/// Helper for updating the screen transition position.
-		/// </summary>
-		bool UpdateTransition (GameTime gameTime, TimeSpan time, int direction)
-		{
-			// How much should we move by?
-			float transitionDelta;
-
-			if (time == TimeSpan.Zero)
-				transitionDelta = 1;
-			else
-				transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / 
-					time.TotalMilliseconds);
-
-			// Update the transition position.
-			transitionPosition += transitionDelta * direction;
-
-			// Did we reach the end of the transition?
-			if (((direction < 0) && (transitionPosition <= 0)) || 
-		((direction > 0) && (transitionPosition >= 1))) {
-				transitionPosition = MathHelper.Clamp (transitionPosition, 0, 1);
-				return false;
-			}
-
-			// Otherwise we are still busy transitioning.
-			return true;
-		}
-
-
-		/// <summary>
-		/// Allows the screen to handle user input. Unlike Update, this method
-		/// is only called when the screen is active, and not when some other
-		/// screen has taken the focus.
-		/// </summary>
-		public virtual void HandleInput (InputState input)
-		{
-		}
-
-
-		/// <summary>
-		/// This is called when the screen should draw itself.
-		/// </summary>
-		public virtual void Draw (GameTime gameTime)
-		{
-		}
-
-
-	#endregion
-
-	#region Public Methods
-
-
-		/// <summary>
-		/// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
-		/// instantly kills the screen, this method respects the transition timings
-		/// and will give the screen a chance to gradually transition off.
-		/// </summary>
-		public void ExitScreen ()
-		{
-			if (TransitionOffTime == TimeSpan.Zero) {
-				// If the screen has a zero transition time, remove it immediately.
-				ScreenManager.RemoveScreen (this);
-			} else {
-				// Otherwise flag that it should transition off and then exit.
-				isExiting = true;
-			}
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// GameScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input.Touch;
+using System.IO;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// Enum describes the screen transition state.
+	/// </summary>
+	public enum ScreenState
+	{
+		TransitionOn,
+		Active,
+		TransitionOff,
+		Hidden,
+	}
+
+
+	/// <summary>
+	/// A screen is a single layer that has update and draw logic, and which
+	/// can be combined with other layers to build up a complex menu system.
+	/// For instance the main menu, the options menu, the "are you sure you
+	/// want to quit" message box, and the main game itself are all implemented
+	/// as screens.
+	/// </summary>
+	public abstract class GameScreen
+	{
+
+
+		/// <summary>
+		/// Normally when one screen is brought up over the top of another,
+		/// the first screen will transition off to make room for the new
+		/// one. This property indicates whether the screen is only a small
+		/// popup, in which case screens underneath it do not need to bother
+		/// transitioning off.
+		/// </summary>
+		public bool IsPopup
+		{
+			get { return isPopup; }
+			protected set { isPopup = value; }
+		}
+
+		bool isPopup = false;
+
+
+		/// <summary>
+		/// Indicates how long the screen takes to
+		/// transition on when it is activated.
+		/// </summary>
+		public TimeSpan TransitionOnTime
+		{
+			get { return transitionOnTime; }
+			protected set { transitionOnTime = value; }
+		}
+
+		TimeSpan transitionOnTime = TimeSpan.Zero;
+
+
+		/// <summary>
+		/// Indicates how long the screen takes to
+		/// transition off when it is deactivated.
+		/// </summary>
+		public TimeSpan TransitionOffTime
+		{
+			get { return transitionOffTime; }
+			protected set { transitionOffTime = value; }
+		}
+
+		TimeSpan transitionOffTime = TimeSpan.Zero;
+
+
+		/// <summary>
+		/// Gets the current position of the screen transition, ranging
+		/// from zero (fully active, no transition) to one (transitioned
+		/// fully off to nothing).
+		/// </summary>
+		public float TransitionPosition
+		{
+			get { return transitionPosition; }
+			protected set { transitionPosition = value; }
+		}
+
+		float transitionPosition = 1;
+
+
+		/// <summary>
+		/// Gets the current alpha of the screen transition, ranging
+		/// from 1 (fully active, no transition) to 0 (transitioned
+		/// fully off to nothing).
+		/// </summary>
+		public float TransitionAlpha
+		{
+			get { return 1f - TransitionPosition; }
+		}
+
+
+		/// <summary>
+		/// Gets the current screen transition state.
+		/// </summary>
+		public ScreenState ScreenState
+		{
+			get { return screenState; }
+			protected set { screenState = value; }
+		}
+
+		ScreenState screenState = ScreenState.TransitionOn;
+
+
+		/// <summary>
+		/// There are two possible reasons why a screen might be transitioning
+		/// off. It could be temporarily going away to make room for another
+		/// screen that is on top of it, or it could be going away for good.
+		/// This property indicates whether the screen is exiting for real:
+		/// if set, the screen will automatically remove itself as soon as the
+		/// transition finishes.
+		/// </summary>
+		public bool IsExiting
+		{
+			get { return isExiting; }
+			protected internal set { isExiting = value; }
+		}
+
+		bool isExiting = false;
+
+
+		/// <summary>
+		/// Checks whether this screen is active and can respond to user input.
+		/// </summary>
+		public bool IsActive
+		{
+			get
+			{
+				return !otherScreenHasFocus &&
+			(screenState == ScreenState.TransitionOn ||
+			screenState == ScreenState.Active);
+			}
+		}
+
+		bool otherScreenHasFocus;
+
+
+		/// <summary>
+		/// Gets the manager that this screen belongs to.
+		/// </summary>
+		public ScreenManager ScreenManager
+		{
+			get { return screenManager; }
+			internal set { screenManager = value; }
+		}
+
+		ScreenManager screenManager;
+
+
+		/// <summary>
+		/// Gets the index of the player who is currently controlling this screen,
+		/// or null if it is accepting input from any player. This is used to lock
+		/// the game to a specific player profile. The main menu responds to input
+		/// from any connected gamepad, but whichever player makes a selection from
+		/// this menu is given control over all subsequent screens, so other gamepads
+		/// are inactive until the controlling player returns to the main menu.
+		/// </summary>
+		public PlayerIndex? ControllingPlayer
+		{
+			get { return controllingPlayer; }
+			internal set { controllingPlayer = value; }
+		}
+
+		PlayerIndex? controllingPlayer;
+
+
+		/// <summary>
+		/// Gets the gestures the screen is interested in. Screens should be as specific
+		/// as possible with gestures to increase the accuracy of the gesture engine.
+		/// For example, most menus only need Tap or perhaps Tap and VerticalDrag to operate.
+		/// These gestures are handled by the ScreenManager when screens change and
+		/// all gestures are placed in the InputState passed to the HandleInput method.
+		/// </summary>
+		public GestureType EnabledGestures
+		{
+			get { return enabledGestures; }
+			protected set
+			{
+				enabledGestures = value;
+
+				// the screen manager handles this during screen changes, but
+				// if this screen is active and the gesture types are changing,
+				// we have to update the TouchPanel ourself.
+				if (ScreenState == ScreenState.Active)
+				{
+					TouchPanel.EnabledGestures = value;
+				}
+			}
+		}
+
+		GestureType enabledGestures = GestureType.None;
+
+
+
+
+
+		/// <summary>
+		/// Load graphics content for the screen.
+		/// </summary>
+		public virtual void LoadContent()
+		{
+		}
+
+
+		/// <summary>
+		/// Unload content for the screen.
+		/// </summary>
+		public virtual void UnloadContent()
+		{
+		}
+
+
+
+
+
+		/// <summary>
+		/// Allows the screen to run logic, such as updating the transition position.
+		/// Unlike HandleInput, this method is called regardless of whether the screen
+		/// is active, hidden, or in the middle of a transition.
+		/// </summary>
+		public virtual void Update(GameTime gameTime, bool otherScreenHasFocus,
+						bool coveredByOtherScreen)
+		{
+			this.otherScreenHasFocus = otherScreenHasFocus;
+
+			if (isExiting)
+			{
+				// If the screen is going away to die, it should transition off.
+				screenState = ScreenState.TransitionOff;
+
+				if (!UpdateTransition(gameTime, transitionOffTime, 1))
+				{
+					// When the transition finishes, remove the screen.
+					ScreenManager.RemoveScreen(this);
+				}
+			}
+			else if (coveredByOtherScreen)
+			{
+				// If the screen is covered by another, it should transition off.
+				if (UpdateTransition(gameTime, transitionOffTime, 1))
+				{
+					// Still busy transitioning.
+					screenState = ScreenState.TransitionOff;
+				}
+				else
+				{
+					// Transition finished!
+					screenState = ScreenState.Hidden;
+				}
+			}
+			else
+			{
+				// Otherwise the screen should transition on and become active.
+				if (UpdateTransition(gameTime, transitionOnTime, -1))
+				{
+					// Still busy transitioning.
+					screenState = ScreenState.TransitionOn;
+				}
+				else
+				{
+					// Transition finished!
+					screenState = ScreenState.Active;
+				}
+			}
+		}
+
+
+		/// <summary>
+		/// Helper for updating the screen transition position.
+		/// </summary>
+		bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
+		{
+			// How much should we move by?
+			float transitionDelta;
+
+			if (time == TimeSpan.Zero)
+				transitionDelta = 1;
+			else
+				transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
+					time.TotalMilliseconds);
+
+			// Update the transition position.
+			transitionPosition += transitionDelta * direction;
+
+			// Did we reach the end of the transition?
+			if (((direction < 0) && (transitionPosition <= 0)) ||
+		((direction > 0) && (transitionPosition >= 1)))
+			{
+				transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
+				return false;
+			}
+
+			// Otherwise we are still busy transitioning.
+			return true;
+		}
+
+
+		/// <summary>
+		/// Allows the screen to handle user input. Unlike Update, this method
+		/// is only called when the screen is active, and not when some other
+		/// screen has taken the focus.
+		/// </summary>
+		public virtual void HandleInput(InputState input)
+		{
+		}
+
+
+		/// <summary>
+		/// This is called when the screen should draw itself.
+		/// </summary>
+		public virtual void Draw(GameTime gameTime)
+		{
+		}
+
+
+
+
+
+		/// <summary>
+		/// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
+		/// instantly kills the screen, this method respects the transition timings
+		/// and will give the screen a chance to gradually transition off.
+		/// </summary>
+		public void ExitScreen()
+		{
+			if (TransitionOffTime == TimeSpan.Zero)
+			{
+				// If the screen has a zero transition time, remove it immediately.
+				ScreenManager.RemoveScreen(this);
+			}
+			else
+			{
+				// Otherwise flag that it should transition off and then exit.
+				isExiting = true;
+			}
+		}
+
+
+	}
+}

+ 227 - 237
NetworkStateManagement/ScreenManager/InputState.cs → NetworkStateManagement/Core/ScreenManager/InputState.cs

@@ -1,237 +1,227 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// InputState.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Input.Touch;
-using System.Collections.Generic;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Helper for reading input from keyboard, gamepad, and touch input. This class 
-    /// tracks both the current and previous state of the input devices, and implements 
-    /// query methods for high level input actions such as "move up through the menu"
-    /// or "pause the game".
-    /// </summary>
-    public class InputState
-    {
-        #region Fields
-
-        public const int MaxInputs = 4;
-
-        public readonly KeyboardState[] CurrentKeyboardStates;
-        public readonly GamePadState[] CurrentGamePadStates;
-
-        public readonly KeyboardState[] LastKeyboardStates;
-        public readonly GamePadState[] LastGamePadStates;
-
-        public readonly bool[] GamePadWasConnected;
-
-        public TouchCollection TouchState;
-
-        public readonly List<GestureSample> Gestures = new List<GestureSample>();
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new input state.
-        /// </summary>
-        public InputState()
-        {
-            CurrentKeyboardStates = new KeyboardState[MaxInputs];
-            CurrentGamePadStates = new GamePadState[MaxInputs];
-
-            LastKeyboardStates = new KeyboardState[MaxInputs];
-            LastGamePadStates = new GamePadState[MaxInputs];
-
-            GamePadWasConnected = new bool[MaxInputs];
-        }
-
-
-        #endregion
-
-        #region Public Methods
-
-
-        /// <summary>
-        /// Reads the latest state of the keyboard and gamepad.
-        /// </summary>
-        public void Update()
-        {
-            for (int i = 0; i < MaxInputs; i++)
-            {
-                LastKeyboardStates[i] = CurrentKeyboardStates[i];
-                LastGamePadStates[i] = CurrentGamePadStates[i];
-
-                CurrentKeyboardStates[i] = Keyboard.GetState((PlayerIndex)i);
-                CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
-
-                // Keep track of whether a gamepad has ever been
-                // connected, so we can detect if it is unplugged.
-                if (CurrentGamePadStates[i].IsConnected)
-                {
-                    GamePadWasConnected[i] = true;
-                }
-            }
-
-            TouchState = TouchPanel.GetState();
-
-            Gestures.Clear();
-            while (TouchPanel.IsGestureAvailable)
-            {
-                Gestures.Add(TouchPanel.ReadGesture());
-            }
-        }
-
-
-        /// <summary>
-        /// Helper for checking if a key was newly pressed during this update. The
-        /// controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When a keypress
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer,
-                                            out PlayerIndex playerIndex)
-        {
-            if (controllingPlayer.HasValue)
-            {
-                // Read input from the specified player.
-                playerIndex = controllingPlayer.Value;
-
-                int i = (int)playerIndex;
-
-                return (CurrentKeyboardStates[i].IsKeyDown(key) &&
-                        LastKeyboardStates[i].IsKeyUp(key));
-            }
-            else
-            {
-                // Accept input from any player.
-                return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
-                        IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
-                        IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
-                        IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
-            }
-        }
-
-
-        /// <summary>
-        /// Helper for checking if a button was newly pressed during this update.
-        /// The controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When a button press
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer,
-                                                     out PlayerIndex playerIndex)
-        {
-            if (controllingPlayer.HasValue)
-            {
-                // Read input from the specified player.
-                playerIndex = controllingPlayer.Value;
-
-                int i = (int)playerIndex;
-
-                return (CurrentGamePadStates[i].IsButtonDown(button) &&
-                        LastGamePadStates[i].IsButtonUp(button));
-            }
-            else
-            {
-                // Accept input from any player.
-                return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
-                        IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
-                        IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
-                        IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
-            }
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu select" input action.
-        /// The controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When the action
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsMenuSelect(PlayerIndex? controllingPlayer,
-                                 out PlayerIndex playerIndex)
-        {
-            return IsNewKeyPress(Keys.Space, controllingPlayer, out playerIndex) ||
-                   IsNewKeyPress(Keys.Enter, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.A, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu cancel" input action.
-        /// The controllingPlayer parameter specifies which player to read input for.
-        /// If this is null, it will accept input from any player. When the action
-        /// is detected, the output playerIndex reports which player pressed it.
-        /// </summary>
-        public bool IsMenuCancel(PlayerIndex? controllingPlayer,
-                                 out PlayerIndex playerIndex)
-        {
-            return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.B, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu up" input action.
-        /// The controllingPlayer parameter specifies which player to read
-        /// input for. If this is null, it will accept input from any player.
-        /// </summary>
-        public bool IsMenuUp(PlayerIndex? controllingPlayer)
-        {
-            PlayerIndex playerIndex;
-
-            return IsNewKeyPress(Keys.Up, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.DPadUp, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "menu down" input action.
-        /// The controllingPlayer parameter specifies which player to read
-        /// input for. If this is null, it will accept input from any player.
-        /// </summary>
-        public bool IsMenuDown(PlayerIndex? controllingPlayer)
-        {
-            PlayerIndex playerIndex;
-
-            return IsNewKeyPress(Keys.Down, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.DPadDown, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex);
-        }
-
-
-        /// <summary>
-        /// Checks for a "pause the game" input action.
-        /// The controllingPlayer parameter specifies which player to read
-        /// input for. If this is null, it will accept input from any player.
-        /// </summary>
-        public bool IsPauseGame(PlayerIndex? controllingPlayer)
-        {
-            PlayerIndex playerIndex;
-
-            return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex) ||
-                   IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// InputState.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Input.Touch;
+using System.Collections.Generic;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Helper for reading input from keyboard, gamepad, and touch input. This class 
+    /// tracks both the current and previous state of the input devices, and implements 
+    /// query methods for high level input actions such as "move up through the menu"
+    /// or "pause the game".
+    /// </summary>
+    public class InputState
+    {
+
+        public const int MaxInputs = 4;
+
+        public readonly KeyboardState[] CurrentKeyboardStates;
+        public readonly GamePadState[] CurrentGamePadStates;
+
+        public readonly KeyboardState[] LastKeyboardStates;
+        public readonly GamePadState[] LastGamePadStates;
+
+        public readonly bool[] GamePadWasConnected;
+
+        public TouchCollection TouchState;
+
+        public readonly List<GestureSample> Gestures = new List<GestureSample>();
+
+
+
+
+        /// <summary>
+        /// Constructs a new input state.
+        /// </summary>
+        public InputState()
+        {
+            CurrentKeyboardStates = new KeyboardState[MaxInputs];
+            CurrentGamePadStates = new GamePadState[MaxInputs];
+
+            LastKeyboardStates = new KeyboardState[MaxInputs];
+            LastGamePadStates = new GamePadState[MaxInputs];
+
+            GamePadWasConnected = new bool[MaxInputs];
+        }
+
+
+
+
+
+        /// <summary>
+        /// Reads the latest state of the keyboard and gamepad.
+        /// </summary>
+        public void Update()
+        {
+            for (int i = 0; i < MaxInputs; i++)
+            {
+                LastKeyboardStates[i] = CurrentKeyboardStates[i];
+                LastGamePadStates[i] = CurrentGamePadStates[i];
+
+                CurrentKeyboardStates[i] = Keyboard.GetState((PlayerIndex)i);
+                CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
+
+                // Keep track of whether a gamepad has ever been
+                // connected, so we can detect if it is unplugged.
+                if (CurrentGamePadStates[i].IsConnected)
+                {
+                    GamePadWasConnected[i] = true;
+                }
+            }
+
+            TouchState = TouchPanel.GetState();
+
+            Gestures.Clear();
+            while (TouchPanel.IsGestureAvailable)
+            {
+                Gestures.Add(TouchPanel.ReadGesture());
+            }
+        }
+
+
+        /// <summary>
+        /// Helper for checking if a key was newly pressed during this update. The
+        /// controllingPlayer parameter specifies which player to read input for.
+        /// If this is null, it will accept input from any player. When a keypress
+        /// is detected, the output playerIndex reports which player pressed it.
+        /// </summary>
+        public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer,
+                                            out PlayerIndex playerIndex)
+        {
+            if (controllingPlayer.HasValue)
+            {
+                // Read input from the specified player.
+                playerIndex = controllingPlayer.Value;
+
+                int i = (int)playerIndex;
+
+                return (CurrentKeyboardStates[i].IsKeyDown(key) &&
+                        LastKeyboardStates[i].IsKeyUp(key));
+            }
+            else
+            {
+                // Accept input from any player.
+                return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
+                        IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
+                        IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
+                        IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
+            }
+        }
+
+
+        /// <summary>
+        /// Helper for checking if a button was newly pressed during this update.
+        /// The controllingPlayer parameter specifies which player to read input for.
+        /// If this is null, it will accept input from any player. When a button press
+        /// is detected, the output playerIndex reports which player pressed it.
+        /// </summary>
+        public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer,
+                                                     out PlayerIndex playerIndex)
+        {
+            if (controllingPlayer.HasValue)
+            {
+                // Read input from the specified player.
+                playerIndex = controllingPlayer.Value;
+
+                int i = (int)playerIndex;
+
+                return (CurrentGamePadStates[i].IsButtonDown(button) &&
+                        LastGamePadStates[i].IsButtonUp(button));
+            }
+            else
+            {
+                // Accept input from any player.
+                return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
+                        IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
+                        IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
+                        IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu select" input action.
+        /// The controllingPlayer parameter specifies which player to read input for.
+        /// If this is null, it will accept input from any player. When the action
+        /// is detected, the output playerIndex reports which player pressed it.
+        /// </summary>
+        public bool IsMenuSelect(PlayerIndex? controllingPlayer,
+                                 out PlayerIndex playerIndex)
+        {
+            return IsNewKeyPress(Keys.Space, controllingPlayer, out playerIndex) ||
+                   IsNewKeyPress(Keys.Enter, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.A, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu cancel" input action.
+        /// The controllingPlayer parameter specifies which player to read input for.
+        /// If this is null, it will accept input from any player. When the action
+        /// is detected, the output playerIndex reports which player pressed it.
+        /// </summary>
+        public bool IsMenuCancel(PlayerIndex? controllingPlayer,
+                                 out PlayerIndex playerIndex)
+        {
+            return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.B, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex);
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu up" input action.
+        /// The controllingPlayer parameter specifies which player to read
+        /// input for. If this is null, it will accept input from any player.
+        /// </summary>
+        public bool IsMenuUp(PlayerIndex? controllingPlayer)
+        {
+            PlayerIndex playerIndex;
+
+            return IsNewKeyPress(Keys.Up, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.DPadUp, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex);
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu down" input action.
+        /// The controllingPlayer parameter specifies which player to read
+        /// input for. If this is null, it will accept input from any player.
+        /// </summary>
+        public bool IsMenuDown(PlayerIndex? controllingPlayer)
+        {
+            PlayerIndex playerIndex;
+
+            return IsNewKeyPress(Keys.Down, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.DPadDown, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex);
+        }
+
+
+        /// <summary>
+        /// Checks for a "pause the game" input action.
+        /// The controllingPlayer parameter specifies which player to read
+        /// input for. If this is null, it will accept input from any player.
+        /// </summary>
+        public bool IsPauseGame(PlayerIndex? controllingPlayer)
+        {
+            PlayerIndex playerIndex;
+
+            return IsNewKeyPress(Keys.Escape, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex) ||
+                   IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex);
+        }
+
+
+    }
+}

+ 301 - 315
NetworkStateManagement/ScreenManager/ScreenManager.cs → NetworkStateManagement/Core/ScreenManager/ScreenManager.cs

@@ -1,315 +1,301 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// ScreenManager.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Diagnostics;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input.Touch;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// The screen manager is a component which manages one or more GameScreen
-    /// instances. It maintains a stack of screens, calls their Update and Draw
-    /// methods at the appropriate times, and automatically routes input to the
-    /// topmost active screen.
-    /// </summary>
-    public class ScreenManager : DrawableGameComponent
-    {
-        #region Fields
-
-        List<GameScreen> screens = new List<GameScreen>();
-        List<GameScreen> screensToUpdate = new List<GameScreen>();
-
-        InputState input = new InputState();
-
-        SpriteBatch spriteBatch;
-        SpriteFont font;
-        Texture2D blankTexture;
-
-        bool isInitialized;
-
-        bool traceEnabled;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// A default SpriteBatch shared by all the screens. This saves
-        /// each screen having to bother creating their own local instance.
-        /// </summary>
-        public SpriteBatch SpriteBatch
-        {
-            get { return spriteBatch; }
-        }
-
-
-        /// <summary>
-        /// A default font shared by all the screens. This saves
-        /// each screen having to bother loading their own local copy.
-        /// </summary>
-        public SpriteFont Font
-        {
-            get { return font; }
-        }
-
-
-        /// <summary>
-        /// If true, the manager prints out a list of all the screens
-        /// each time it is updated. This can be useful for making sure
-        /// everything is being added and removed at the right times.
-        /// </summary>
-        public bool TraceEnabled
-        {
-            get { return traceEnabled; }
-            set { traceEnabled = value; }
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new screen manager component.
-        /// </summary>
-        public ScreenManager(Game game)
-            : base(game)
-        {
-            // we must set EnabledGestures before we can query for them, but
-            // we don't assume the game wants to read them.
-            TouchPanel.EnabledGestures = GestureType.None;
-        }
-
-
-        /// <summary>
-        /// Initializes the screen manager component.
-        /// </summary>
-        public override void Initialize()
-        {
-            base.Initialize();
-
-            isInitialized = true;
-        }
-
-
-        /// <summary>
-        /// Load your graphics content.
-        /// </summary>
-        protected override void LoadContent()
-        {
-            // Load content belonging to the screen manager.
-            ContentManager content = Game.Content;
-
-            spriteBatch = new SpriteBatch(GraphicsDevice);
-            font = content.Load<SpriteFont>("menufont");
-            blankTexture = content.Load<Texture2D>("blank");
-
-            // Tell each of the screens to load their content.
-            foreach (GameScreen screen in screens)
-            {
-                screen.LoadContent();
-            }
-        }
-
-
-        /// <summary>
-        /// Unload your graphics content.
-        /// </summary>
-        protected override void UnloadContent()
-        {
-            // Tell each of the screens to unload their content.
-            foreach (GameScreen screen in screens)
-            {
-                screen.UnloadContent();
-            }
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Allows each screen to run logic.
-        /// </summary>
-        public override void Update(GameTime gameTime)
-        {
-            // Read the keyboard and gamepad.
-            input.Update();
-
-            // Make a copy of the master screen list, to avoid confusion if
-            // the process of updating one screen adds or removes others.
-            screensToUpdate.Clear();
-
-            foreach (GameScreen screen in screens)
-                screensToUpdate.Add(screen);
-
-            bool otherScreenHasFocus = !Game.IsActive;
-            bool coveredByOtherScreen = false;
-
-            // Loop as long as there are screens waiting to be updated.
-            while (screensToUpdate.Count > 0)
-            {
-                // Pop the topmost screen off the waiting list.
-                GameScreen screen = screensToUpdate[screensToUpdate.Count - 1];
-
-                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);
-
-                // Update the screen.
-                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-                if (screen.ScreenState == ScreenState.TransitionOn ||
-                    screen.ScreenState == ScreenState.Active)
-                {
-                    // If this is the first active screen we came across,
-                    // give it a chance to handle input.
-                    if (!otherScreenHasFocus)
-                    {
-                        screen.HandleInput(input);
-
-                        otherScreenHasFocus = true;
-                    }
-
-                    // If this is an active non-popup, inform any subsequent
-                    // screens that they are covered by it.
-                    if (!screen.IsPopup)
-                        coveredByOtherScreen = true;
-                }
-            }
-
-            // Print debug trace?
-            if (traceEnabled)
-                TraceScreens();
-        }
-
-
-        /// <summary>
-        /// Prints a list of all the screens, for debugging.
-        /// </summary>
-        void TraceScreens()
-        {
-            List<string> screenNames = new List<string>();
-
-            foreach (GameScreen screen in screens)
-                screenNames.Add(screen.GetType().Name);
-
-            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
-        }
-
-
-        /// <summary>
-        /// Tells each screen to draw itself.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            foreach (GameScreen screen in screens)
-            {
-                if (screen.ScreenState == ScreenState.Hidden)
-                    continue;
-
-                screen.Draw(gameTime);
-            }
-        }
-
-
-        #endregion
-
-        #region Public Methods
-
-
-        /// <summary>
-        /// Adds a new screen to the screen manager.
-        /// </summary>
-        public void AddScreen(GameScreen screen, PlayerIndex? controllingPlayer)
-        {
-            screen.ControllingPlayer = controllingPlayer;
-            screen.ScreenManager = this;
-            screen.IsExiting = false;
-
-            // If we have a graphics device, tell the screen to load content.
-            if (isInitialized)
-            {
-                screen.LoadContent();
-            }
-
-            screens.Add(screen);
-
-            // update the TouchPanel to respond to gestures this screen is interested in
-            TouchPanel.EnabledGestures = screen.EnabledGestures;
-        }
-
-
-        /// <summary>
-        /// Removes a screen from the screen manager. You should normally
-        /// use GameScreen.ExitScreen instead of calling this directly, so
-        /// the screen can gradually transition off rather than just being
-        /// instantly removed.
-        /// </summary>
-        public void RemoveScreen(GameScreen screen)
-        {
-            // If we have a graphics device, tell the screen to unload content.
-            if (isInitialized)
-            {
-                screen.UnloadContent();
-            }
-
-            screens.Remove(screen);
-            screensToUpdate.Remove(screen);
-
-            // if there is a screen still in the manager, update TouchPanel
-            // to respond to gestures that screen is interested in.
-            if (screens.Count > 0)
-            {
-                TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
-            }
-        }
-
-
-        /// <summary>
-        /// Expose an array holding all the screens. We return a copy rather
-        /// than the real master list, because screens should only ever be added
-        /// or removed using the AddScreen and RemoveScreen methods.
-        /// </summary>
-        public GameScreen[] GetScreens()
-        {
-            return screens.ToArray();
-        }
-
-
-        /// <summary>
-        /// Helper draws a translucent black fullscreen sprite, used for fading
-        /// screens in and out, and for darkening the background behind popups.
-        /// </summary>
-        public void FadeBackBufferToBlack(float alpha)
-        {
-            Viewport viewport = GraphicsDevice.Viewport;
-
-            spriteBatch.Begin();
-
-            spriteBatch.Draw(blankTexture,
-                             new Rectangle(0, 0, viewport.Width, viewport.Height),
-                             Color.Black * alpha);
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// ScreenManager.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input.Touch;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// The screen manager is a component which manages one or more GameScreen
+    /// instances. It maintains a stack of screens, calls their Update and Draw
+    /// methods at the appropriate times, and automatically routes input to the
+    /// topmost active screen.
+    /// </summary>
+    public class ScreenManager : DrawableGameComponent
+    {
+
+        List<GameScreen> screens = new List<GameScreen>();
+        List<GameScreen> screensToUpdate = new List<GameScreen>();
+
+        InputState input = new InputState();
+
+        SpriteBatch spriteBatch;
+        SpriteFont font;
+        Texture2D blankTexture;
+
+        bool isInitialized;
+
+        bool traceEnabled;
+
+
+
+
+        /// <summary>
+        /// A default SpriteBatch shared by all the screens. This saves
+        /// each screen having to bother creating their own local instance.
+        /// </summary>
+        public SpriteBatch SpriteBatch
+        {
+            get { return spriteBatch; }
+        }
+
+
+        /// <summary>
+        /// A default font shared by all the screens. This saves
+        /// each screen having to bother loading their own local copy.
+        /// </summary>
+        public SpriteFont Font
+        {
+            get { return font; }
+        }
+
+
+        /// <summary>
+        /// If true, the manager prints out a list of all the screens
+        /// each time it is updated. This can be useful for making sure
+        /// everything is being added and removed at the right times.
+        /// </summary>
+        public bool TraceEnabled
+        {
+            get { return traceEnabled; }
+            set { traceEnabled = value; }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Constructs a new screen manager component.
+        /// </summary>
+        public ScreenManager(Game game)
+            : base(game)
+        {
+            // we must set EnabledGestures before we can query for them, but
+            // we don't assume the game wants to read them.
+            TouchPanel.EnabledGestures = GestureType.None;
+        }
+
+
+        /// <summary>
+        /// Initializes the screen manager component.
+        /// </summary>
+        public override void Initialize()
+        {
+            base.Initialize();
+
+            isInitialized = true;
+        }
+
+
+        /// <summary>
+        /// Load your graphics content.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            // Load content belonging to the screen manager.
+            ContentManager content = Game.Content;
+
+            spriteBatch = new SpriteBatch(GraphicsDevice);
+            font = content.Load<SpriteFont>("menufont");
+            blankTexture = content.Load<Texture2D>("blank");
+
+            // Tell each of the screens to load their content.
+            foreach (GameScreen screen in screens)
+            {
+                screen.LoadContent();
+            }
+        }
+
+
+        /// <summary>
+        /// Unload your graphics content.
+        /// </summary>
+        protected override void UnloadContent()
+        {
+            // Tell each of the screens to unload their content.
+            foreach (GameScreen screen in screens)
+            {
+                screen.UnloadContent();
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Allows each screen to run logic.
+        /// </summary>
+        public override void Update(GameTime gameTime)
+        {
+            // Read the keyboard and gamepad.
+            input.Update();
+
+            // Make a copy of the master screen list, to avoid confusion if
+            // the process of updating one screen adds or removes others.
+            screensToUpdate.Clear();
+
+            foreach (GameScreen screen in screens)
+                screensToUpdate.Add(screen);
+
+            bool otherScreenHasFocus = !Game.IsActive;
+            bool coveredByOtherScreen = false;
+
+            // Loop as long as there are screens waiting to be updated.
+            while (screensToUpdate.Count > 0)
+            {
+                // Pop the topmost screen off the waiting list.
+                GameScreen screen = screensToUpdate[screensToUpdate.Count - 1];
+
+                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);
+
+                // Update the screen.
+                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+                if (screen.ScreenState == ScreenState.TransitionOn ||
+                    screen.ScreenState == ScreenState.Active)
+                {
+                    // If this is the first active screen we came across,
+                    // give it a chance to handle input.
+                    if (!otherScreenHasFocus)
+                    {
+                        screen.HandleInput(input);
+
+                        otherScreenHasFocus = true;
+                    }
+
+                    // If this is an active non-popup, inform any subsequent
+                    // screens that they are covered by it.
+                    if (!screen.IsPopup)
+                        coveredByOtherScreen = true;
+                }
+            }
+
+            // Print debug trace?
+            if (traceEnabled)
+                TraceScreens();
+        }
+
+
+        /// <summary>
+        /// Prints a list of all the screens, for debugging.
+        /// </summary>
+        void TraceScreens()
+        {
+            List<string> screenNames = new List<string>();
+
+            foreach (GameScreen screen in screens)
+                screenNames.Add(screen.GetType().Name);
+
+            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
+        }
+
+
+        /// <summary>
+        /// Tells each screen to draw itself.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            foreach (GameScreen screen in screens)
+            {
+                if (screen.ScreenState == ScreenState.Hidden)
+                    continue;
+
+                screen.Draw(gameTime);
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Adds a new screen to the screen manager.
+        /// </summary>
+        public void AddScreen(GameScreen screen, PlayerIndex? controllingPlayer)
+        {
+            screen.ControllingPlayer = controllingPlayer;
+            screen.ScreenManager = this;
+            screen.IsExiting = false;
+
+            // If we have a graphics device, tell the screen to load content.
+            if (isInitialized)
+            {
+                screen.LoadContent();
+            }
+
+            screens.Add(screen);
+
+            // update the TouchPanel to respond to gestures this screen is interested in
+            TouchPanel.EnabledGestures = screen.EnabledGestures;
+        }
+
+
+        /// <summary>
+        /// Removes a screen from the screen manager. You should normally
+        /// use GameScreen.ExitScreen instead of calling this directly, so
+        /// the screen can gradually transition off rather than just being
+        /// instantly removed.
+        /// </summary>
+        public void RemoveScreen(GameScreen screen)
+        {
+            // If we have a graphics device, tell the screen to unload content.
+            if (isInitialized)
+            {
+                screen.UnloadContent();
+            }
+
+            screens.Remove(screen);
+            screensToUpdate.Remove(screen);
+
+            // if there is a screen still in the manager, update TouchPanel
+            // to respond to gestures that screen is interested in.
+            if (screens.Count > 0)
+            {
+                TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
+            }
+        }
+
+
+        /// <summary>
+        /// Expose an array holding all the screens. We return a copy rather
+        /// than the real master list, because screens should only ever be added
+        /// or removed using the AddScreen and RemoveScreen methods.
+        /// </summary>
+        public GameScreen[] GetScreens()
+        {
+            return screens.ToArray();
+        }
+
+
+        /// <summary>
+        /// Helper draws a translucent black fullscreen sprite, used for fading
+        /// screens in and out, and for darkening the background behind popups.
+        /// </summary>
+        public void FadeBackBufferToBlack(float alpha)
+        {
+            Viewport viewport = GraphicsDevice.Viewport;
+
+            spriteBatch.Begin();
+
+            spriteBatch.Draw(blankTexture,
+                             new Rectangle(0, 0, viewport.Width, viewport.Height),
+                             Color.Black * alpha);
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 100 - 110
NetworkStateManagement/Screens/BackgroundScreen.cs → NetworkStateManagement/Core/Screens/BackgroundScreen.cs

@@ -1,110 +1,100 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// BackgroundScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// The background screen sits behind all the other menu screens.
-    /// It draws a background image that remains fixed in place regardless
-    /// of whatever transitions the screens on top of it may be doing.
-    /// </summary>
-    class BackgroundScreen : GameScreen
-    {
-        #region Fields
-
-        ContentManager content;
-        Texture2D backgroundTexture;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public BackgroundScreen()
-        {
-            TransitionOnTime = TimeSpan.FromSeconds(0.5);
-            TransitionOffTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        /// <summary>
-        /// Loads graphics content for this screen. The background texture is quite
-        /// big, so we use our own local ContentManager to load it. This allows us
-        /// to unload before going from the menus into the game itself, wheras if we
-        /// used the shared ContentManager provided by the Game class, the content
-        /// would remain loaded forever.
-        /// </summary>
-        public override void LoadContent()
-        {
-            if (content == null)
-                content = new ContentManager(ScreenManager.Game.Services, "Content");
-
-            backgroundTexture = content.Load<Texture2D>("background");
-        }
-
-
-        /// <summary>
-        /// Unloads graphics content for this screen.
-        /// </summary>
-        public override void UnloadContent()
-        {
-            content.Unload();
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the background screen. Unlike most screens, this should not
-        /// transition off even if it has been covered by another screen: it is
-        /// supposed to be covered, after all! This overload forces the
-        /// coveredByOtherScreen parameter to false in order to stop the base
-        /// Update method wanting to transition off.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, false);
-        }
-
-
-        /// <summary>
-        /// Draws the background screen.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-            Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);
-
-            spriteBatch.Begin();
-
-            spriteBatch.Draw(backgroundTexture, fullscreen,
-                             new Color(TransitionAlpha, TransitionAlpha, TransitionAlpha));
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// BackgroundScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// The background screen sits behind all the other menu screens.
+    /// It draws a background image that remains fixed in place regardless
+    /// of whatever transitions the screens on top of it may be doing.
+    /// </summary>
+    class BackgroundScreen : GameScreen
+    {
+
+        ContentManager content;
+        Texture2D backgroundTexture;
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public BackgroundScreen()
+        {
+            TransitionOnTime = TimeSpan.FromSeconds(0.5);
+            TransitionOffTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+        /// <summary>
+        /// Loads graphics content for this screen. The background texture is quite
+        /// big, so we use our own local ContentManager to load it. This allows us
+        /// to unload before going from the menus into the game itself, wheras if we
+        /// used the shared ContentManager provided by the Game class, the content
+        /// would remain loaded forever.
+        /// </summary>
+        public override void LoadContent()
+        {
+            if (content == null)
+                content = new ContentManager(ScreenManager.Game.Services, "Content");
+
+            backgroundTexture = content.Load<Texture2D>("background");
+        }
+
+
+        /// <summary>
+        /// Unloads graphics content for this screen.
+        /// </summary>
+        public override void UnloadContent()
+        {
+            content.Unload();
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the background screen. Unlike most screens, this should not
+        /// transition off even if it has been covered by another screen: it is
+        /// supposed to be covered, after all! This overload forces the
+        /// coveredByOtherScreen parameter to false in order to stop the base
+        /// Update method wanting to transition off.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, false);
+        }
+
+
+        /// <summary>
+        /// Draws the background screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Rectangle fullscreen = new Rectangle(0, 0, viewport.Width, viewport.Height);
+
+            spriteBatch.Begin();
+
+            spriteBatch.Draw(backgroundTexture, fullscreen,
+                             new Color(TransitionAlpha, TransitionAlpha, TransitionAlpha));
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 283 - 293
NetworkStateManagement/Screens/GameplayScreen.cs → NetworkStateManagement/Core/Screens/GameplayScreen.cs

@@ -1,293 +1,283 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// GameplayScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Threading;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input;
-using Microsoft.Xna.Framework.Net;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// This screen implements the actual game logic. It is just a
-    /// placeholder to get the idea across: you'll probably want to
-    /// put some more interesting gameplay in here!
-    /// </summary>
-    class GameplayScreen : GameScreen
-    {
-        #region Fields
-
-        NetworkSession networkSession;
-
-        ContentManager content;
-        SpriteFont gameFont;
-
-        Vector2 playerPosition = new Vector2(100, 100);
-        Vector2 enemyPosition = new Vector2(100, 100);
-
-        Random random = new Random();
-
-        float pauseAlpha;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// The logic for deciding whether the game is paused depends on whether
-        /// this is a networked or single player game. If we are in a network session,
-        /// we should go on updating the game even when the user tabs away from us or
-        /// brings up the pause menu, because even though the local player is not
-        /// responding to input, other remote players may not be paused. In single
-        /// player modes, however, we want everything to pause if the game loses focus.
-        /// </summary>
-        new bool IsActive
-        {
-            get
-            {
-                if (networkSession == null)
-                {
-                    // Pause behavior for single player games.
-                    return base.IsActive;
-                }
-                else
-                {
-                    // Pause behavior for networked games.
-                    return !IsExiting;
-                }
-            }
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public GameplayScreen(NetworkSession networkSession)
-        {
-            this.networkSession = networkSession;
-
-            TransitionOnTime = TimeSpan.FromSeconds(1.5);
-            TransitionOffTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        /// <summary>
-        /// Load graphics content for the game.
-        /// </summary>
-        public override void LoadContent()
-        {
-            if (content == null)
-                content = new ContentManager(ScreenManager.Game.Services, "Content");
-
-            gameFont = content.Load<SpriteFont>("gamefont");
-
-            // A real game would probably have more content than this sample, so
-            // it would take longer to load. We simulate that by delaying for a
-            // while, giving you a chance to admire the beautiful loading screen.
-            Thread.Sleep(1000);
-
-            // once the load has finished, we use ResetElapsedTime to tell the game's
-            // timing mechanism that we have just finished a very long frame, and that
-            // it should not try to catch up.
-            ScreenManager.Game.ResetElapsedTime();
-        }
-
-
-        /// <summary>
-        /// Unload graphics content used by the game.
-        /// </summary>
-        public override void UnloadContent()
-        {
-            content.Unload();
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the state of the game.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, false);
-
-            // Gradually fade in or out depending on whether we are covered by the pause screen.
-            if (coveredByOtherScreen)
-                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
-            else
-                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
-
-            if (IsActive)
-            {
-                // Apply some random jitter to make the enemy move around.
-                const float randomization = 10;
-
-                enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
-                enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
-
-                // Apply a stabilizing force to stop the enemy moving off the screen.
-                Vector2 targetPosition = new Vector2(200, 200);
-
-                enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
-
-                // TODO: this game isn't very fun! You could probably improve
-                // it by inserting something more interesting in this space :-)
-            }
-
-            // If we are in a network game, check if we should return to the lobby.
-            if ((networkSession != null) && !IsExiting)
-            {
-                if (networkSession.SessionState == NetworkSessionState.Lobby)
-                {
-                    LoadingScreen.Load(ScreenManager, true, null,
-                                       new BackgroundScreen(),
-                                       new LobbyScreen(networkSession));
-                }
-            }
-        }
-
-
-        /// <summary>
-        /// Lets the game respond to player input. Unlike the Update method,
-        /// this will only be called when the gameplay screen is active.
-        /// </summary>
-        public override void HandleInput(InputState input)
-        {
-            if (input == null)
-                throw new ArgumentNullException("input");
-
-            if (ControllingPlayer.HasValue)
-            {
-                // In single player games, handle input for the controlling player.
-                HandlePlayerInput(input, ControllingPlayer.Value);
-            }
-            else if (networkSession != null)
-            {
-                // In network game modes, handle input for all the
-                // local players who are participating in the session.
-                foreach (LocalNetworkGamer gamer in networkSession.LocalGamers)
-                {
-                    if (!HandlePlayerInput(input, gamer.SignedInGamer.PlayerIndex))
-                        break;
-                }
-            }
-        }
-
-
-        /// <summary>
-        /// Handles input for the specified player. In local game modes, this is called
-        /// just once for the controlling player. In network modes, it can be called
-        /// more than once if there are multiple profiles playing on the local machine.
-        /// Returns true if we should continue to handle input for subsequent players,
-        /// or false if this player has paused the game.
-        /// </summary>
-        bool HandlePlayerInput(InputState input, PlayerIndex playerIndex)
-        {
-            // Look up inputs for the specified player profile.
-            KeyboardState keyboardState = input.CurrentKeyboardStates[(int)playerIndex];
-            GamePadState gamePadState = input.CurrentGamePadStates[(int)playerIndex];
-
-            // The game pauses either if the user presses the pause button, or if
-            // they unplug the active gamepad. This requires us to keep track of
-            // whether a gamepad was ever plugged in, because we don't want to pause
-            // on PC if they are playing with a keyboard and have no gamepad at all!
-            bool gamePadDisconnected = !gamePadState.IsConnected &&
-                                       input.GamePadWasConnected[(int)playerIndex];
-
-            if (input.IsPauseGame(playerIndex) || gamePadDisconnected)
-            {
-                ScreenManager.AddScreen(new PauseMenuScreen(networkSession), playerIndex);
-                return false;
-            }
-
-            // Otherwise move the player position.
-            Vector2 movement = Vector2.Zero;
-
-            if (keyboardState.IsKeyDown(Keys.Left))
-                movement.X--;
-
-            if (keyboardState.IsKeyDown(Keys.Right))
-                movement.X++;
-
-            if (keyboardState.IsKeyDown(Keys.Up))
-                movement.Y--;
-
-            if (keyboardState.IsKeyDown(Keys.Down))
-                movement.Y++;
-
-            Vector2 thumbstick = gamePadState.ThumbSticks.Left;
-
-            movement.X += thumbstick.X;
-            movement.Y -= thumbstick.Y;
-
-            if (movement.Length() > 1)
-                movement.Normalize();
-
-            playerPosition += movement * 2;
-
-            return true;
-        }
-
-
-        /// <summary>
-        /// Draws the gameplay screen.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            // This game has a blue background. Why? Because!
-            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
-                                               Color.CornflowerBlue, 0, 0);
-
-            // Our player and enemy are both actually just text strings.
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-
-            spriteBatch.Begin();
-
-            spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
-
-            spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
-                                   enemyPosition, Color.DarkRed);
-
-            if (networkSession != null)
-            {
-                string message = "Players: " + networkSession.AllGamers.Count;
-                Vector2 messagePosition = new Vector2(100, 480);
-                spriteBatch.DrawString(gameFont, message, messagePosition, Color.White);
-            }
-
-            spriteBatch.End();
-
-            // If the game is transitioning on or off, fade it out to black.
-            if (TransitionPosition > 0 || pauseAlpha > 0)
-            {
-                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
-
-                ScreenManager.FadeBackBufferToBlack(alpha);
-            }
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// GameplayScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Threading;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Net;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// This screen implements the actual game logic. It is just a
+    /// placeholder to get the idea across: you'll probably want to
+    /// put some more interesting gameplay in here!
+    /// </summary>
+    class GameplayScreen : GameScreen
+    {
+
+        NetworkSession networkSession;
+
+        ContentManager content;
+        SpriteFont gameFont;
+
+        Vector2 playerPosition = new Vector2(100, 100);
+        Vector2 enemyPosition = new Vector2(100, 100);
+
+        Random random = new Random();
+
+        float pauseAlpha;
+
+
+
+
+        /// <summary>
+        /// The logic for deciding whether the game is paused depends on whether
+        /// this is a networked or single player game. If we are in a network session,
+        /// we should go on updating the game even when the user tabs away from us or
+        /// brings up the pause menu, because even though the local player is not
+        /// responding to input, other remote players may not be paused. In single
+        /// player modes, however, we want everything to pause if the game loses focus.
+        /// </summary>
+        new bool IsActive
+        {
+            get
+            {
+                if (networkSession == null)
+                {
+                    // Pause behavior for single player games.
+                    return base.IsActive;
+                }
+                else
+                {
+                    // Pause behavior for networked games.
+                    return !IsExiting;
+                }
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public GameplayScreen(NetworkSession networkSession)
+        {
+            this.networkSession = networkSession;
+
+            TransitionOnTime = TimeSpan.FromSeconds(1.5);
+            TransitionOffTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+        /// <summary>
+        /// Load graphics content for the game.
+        /// </summary>
+        public override void LoadContent()
+        {
+            if (content == null)
+                content = new ContentManager(ScreenManager.Game.Services, "Content");
+
+            gameFont = content.Load<SpriteFont>("gamefont");
+
+            // A real game would probably have more content than this sample, so
+            // it would take longer to load. We simulate that by delaying for a
+            // while, giving you a chance to admire the beautiful loading screen.
+            Thread.Sleep(1000);
+
+            // once the load has finished, we use ResetElapsedTime to tell the game's
+            // timing mechanism that we have just finished a very long frame, and that
+            // it should not try to catch up.
+            ScreenManager.Game.ResetElapsedTime();
+        }
+
+
+        /// <summary>
+        /// Unload graphics content used by the game.
+        /// </summary>
+        public override void UnloadContent()
+        {
+            content.Unload();
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the state of the game.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, false);
+
+            // Gradually fade in or out depending on whether we are covered by the pause screen.
+            if (coveredByOtherScreen)
+                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
+            else
+                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
+
+            if (IsActive)
+            {
+                // Apply some random jitter to make the enemy move around.
+                const float randomization = 10;
+
+                enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
+                enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
+
+                // Apply a stabilizing force to stop the enemy moving off the screen.
+                Vector2 targetPosition = new Vector2(200, 200);
+
+                enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
+
+                // TODO: this game isn't very fun! You could probably improve
+                // it by inserting something more interesting in this space :-)
+            }
+
+            // If we are in a network game, check if we should return to the lobby.
+            if ((networkSession != null) && !IsExiting)
+            {
+                if (networkSession.SessionState == NetworkSessionState.Lobby)
+                {
+                    LoadingScreen.Load(ScreenManager, true, null,
+                                       new BackgroundScreen(),
+                                       new LobbyScreen(networkSession));
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Lets the game respond to player input. Unlike the Update method,
+        /// this will only be called when the gameplay screen is active.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            if (input == null)
+                throw new ArgumentNullException("input");
+
+            if (ControllingPlayer.HasValue)
+            {
+                // In single player games, handle input for the controlling player.
+                HandlePlayerInput(input, ControllingPlayer.Value);
+            }
+            else if (networkSession != null)
+            {
+                // In network game modes, handle input for all the
+                // local players who are participating in the session.
+                foreach (NetworkGamer gamer in networkSession.LocalGamers)
+                {
+                    // TODO: Cast to LocalNetworkGamer if needed, or check if gamer is local
+                    var localGamer = gamer as LocalNetworkGamer ?? (LocalNetworkGamer)gamer;
+                    if (!HandlePlayerInput(input, (PlayerIndex)localGamer.SignedInGamer.PlayerIndex))
+                        break;
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Handles input for the specified player. In local game modes, this is called
+        /// just once for the controlling player. In network modes, it can be called
+        /// more than once if there are multiple profiles playing on the local machine.
+        /// Returns true if we should continue to handle input for subsequent players,
+        /// or false if this player has paused the game.
+        /// </summary>
+        bool HandlePlayerInput(InputState input, PlayerIndex playerIndex)
+        {
+            // Look up inputs for the specified player profile.
+            KeyboardState keyboardState = input.CurrentKeyboardStates[(int)playerIndex];
+            GamePadState gamePadState = input.CurrentGamePadStates[(int)playerIndex];
+
+            // The game pauses either if the user presses the pause button, or if
+            // they unplug the active gamepad. This requires us to keep track of
+            // whether a gamepad was ever plugged in, because we don't want to pause
+            // on PC if they are playing with a keyboard and have no gamepad at all!
+            bool gamePadDisconnected = !gamePadState.IsConnected &&
+                                       input.GamePadWasConnected[(int)playerIndex];
+
+            if (input.IsPauseGame(playerIndex) || gamePadDisconnected)
+            {
+                ScreenManager.AddScreen(new PauseMenuScreen(networkSession), playerIndex);
+                return false;
+            }
+
+            // Otherwise move the player position.
+            Vector2 movement = Vector2.Zero;
+
+            if (keyboardState.IsKeyDown(Keys.Left))
+                movement.X--;
+
+            if (keyboardState.IsKeyDown(Keys.Right))
+                movement.X++;
+
+            if (keyboardState.IsKeyDown(Keys.Up))
+                movement.Y--;
+
+            if (keyboardState.IsKeyDown(Keys.Down))
+                movement.Y++;
+
+            Vector2 thumbstick = gamePadState.ThumbSticks.Left;
+
+            movement.X += thumbstick.X;
+            movement.Y -= thumbstick.Y;
+
+            if (movement.Length() > 1)
+                movement.Normalize();
+
+            playerPosition += movement * 2;
+
+            return true;
+        }
+
+
+        /// <summary>
+        /// Draws the gameplay screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // This game has a blue background. Why? Because!
+            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
+                                               Color.CornflowerBlue, 0, 0);
+
+            // Our player and enemy are both actually just text strings.
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+
+            spriteBatch.Begin();
+
+            spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
+
+            spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
+                                   enemyPosition, Color.DarkRed);
+
+            if (networkSession != null)
+            {
+                string message = "Players: " + networkSession.AllGamers.Count;
+                Vector2 messagePosition = new Vector2(100, 480);
+                spriteBatch.DrawString(gameFont, message, messagePosition, Color.White);
+            }
+
+            spriteBatch.End();
+
+            // If the game is transitioning on or off, fade it out to black.
+            if (TransitionPosition > 0 || pauseAlpha > 0)
+            {
+                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
+
+                ScreenManager.FadeBackBufferToBlack(alpha);
+            }
+        }
+
+
+    }
+}

+ 310 - 306
NetworkStateManagement/Screens/LoadingScreen.cs → NetworkStateManagement/Core/Screens/LoadingScreen.cs

@@ -1,306 +1,310 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// LoadingScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Threading;
-using System.Diagnostics;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Net;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// The loading screen coordinates transitions between the menu system and the
-	/// game itself. Normally one screen will transition off at the same time as
-	/// the next screen is transitioning on, but for larger transitions that can
-	/// take a longer time to load their data, we want the menu system to be entirely
-	/// gone before we start loading the game. This is done as follows:
-	/// 
-	/// - Tell all the existing screens to transition off.
-	/// - Activate a loading screen, which will transition on at the same time.
-	/// - The loading screen watches the state of the previous screens.
-	/// - When it sees they have finished transitioning off, it activates the real
-	///   next screen, which may take a long time to load its data. The loading
-	///   screen will be the only thing displayed while this load is taking place.
-	/// </summary>
-	class LoadingScreen : GameScreen
-	{
-	#region Fields
-
-		bool loadingIsSlow;
-		bool otherScreensAreGone;
-		GameScreen[] screensToLoad;
-		Thread backgroundThread;
-		EventWaitHandle backgroundThreadExit;
-		GraphicsDevice graphicsDevice;
-		NetworkSession networkSession;
-		IMessageDisplay messageDisplay;
-		GameTime loadStartTime;
-		TimeSpan loadAnimationTimer;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// The constructor is private: loading screens should
-		/// be activated via the static Load method instead.
-		/// </summary>
-		private LoadingScreen (ScreenManager screenManager,bool loadingIsSlow, 
-				GameScreen[] screensToLoad)
-			{
-			this.loadingIsSlow = loadingIsSlow;
-			this.screensToLoad = screensToLoad;
-
-			TransitionOnTime = TimeSpan.FromSeconds (0.5);
-
-			// If this is going to be a slow load operation, create a background
-			// thread that will update the network session and draw the load screen
-			// animation while the load is taking place.
-			if (loadingIsSlow) {
-				backgroundThread = new Thread (BackgroundWorkerThread);
-				backgroundThreadExit = new ManualResetEvent (false);
-
-				graphicsDevice = screenManager.GraphicsDevice;
-
-				// Look up some services that will be used by the background thread.
-				IServiceProvider services = screenManager.Game.Services;
-
-				networkSession = (NetworkSession)services.GetService (
-							typeof(NetworkSession));
-
-				messageDisplay = (IMessageDisplay)services.GetService (
-							typeof(IMessageDisplay));
-			}
-		}
-
-
-		/// <summary>
-		/// Activates the loading screen.
-		/// </summary>
-		public static void Load (ScreenManager screenManager, bool loadingIsSlow,
-				PlayerIndex? controllingPlayer,
-				params GameScreen[] screensToLoad)
-		{
-			// Tell all the current screens to transition off.
-			foreach (GameScreen screen in screenManager.GetScreens ())
-				screen.ExitScreen ();
-
-			// Create and activate the loading screen.
-			LoadingScreen loadingScreen = new LoadingScreen (screenManager,
-							loadingIsSlow,
-							screensToLoad);
-
-			screenManager.AddScreen (loadingScreen, controllingPlayer);
-		}
-
-
-	#endregion
-
-	#region Update and Draw
-
-
-		/// <summary>
-		/// Updates the loading screen.
-		/// </summary>
-		public override void Update (GameTime gameTime, bool otherScreenHasFocus,
-							bool coveredByOtherScreen)
-		{
-			base.Update (gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-			// If all the previous screens have finished transitioning
-			// off, it is time to actually perform the load.
-			if (otherScreensAreGone) {
-				// Start up the background thread, which will update the network
-				// session and draw the animation while we are loading.
-				if (backgroundThread != null) {
-					loadStartTime = gameTime;
-					backgroundThread.Start ();
-				}
-
-				// Perform the load operation.
-				ScreenManager.RemoveScreen (this);
-
-				foreach (GameScreen screen in screensToLoad) {
-					if (screen != null) {
-						ScreenManager.AddScreen (screen, ControllingPlayer);
-					}
-				}
-
-				// Signal the background thread to exit, then wait for it to do so.
-				if (backgroundThread != null) {
-					backgroundThreadExit.Set ();
-					backgroundThread.Join ();
-				}
-
-				// Once the load has finished, we use ResetElapsedTime to tell
-				// the  game timing mechanism that we have just finished a very
-				// long frame, and that it should not try to catch up.
-				ScreenManager.Game.ResetElapsedTime ();
-			}
-		}
-
-
-		/// <summary>
-		/// Draws the loading screen.
-		/// </summary>
-		public override void Draw (GameTime gameTime)
-		{
-			// If we are the only active screen, that means all the previous screens
-			// must have finished transitioning off. We check for this in the Draw
-			// method, rather than in Update, because it isn't enough just for the
-			// screens to be gone: in order for the transition to look good we must
-			// have actually drawn a frame without them before we perform the load.
-			if ((ScreenState == ScreenState.Active) && 
-		(ScreenManager.GetScreens ().Length == 1)) {
-				otherScreensAreGone = true;
-			}
-
-			// The gameplay screen takes a while to load, so we display a loading
-			// message while that is going on, but the menus load very quickly, and
-			// it would look silly if we flashed this up for just a fraction of a
-			// second while returning from the game to the menus. This parameter
-			// tells us how long the loading is going to take, so we know whether
-			// to bother drawing the message.
-			if (loadingIsSlow) {
-				SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-				SpriteFont font = ScreenManager.Font;
-
-				string message = Resources.Loading;
-
-				// Center the text in the viewport.
-				Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-				Vector2 viewportSize = new Vector2 (viewport.Width, viewport.Height);
-				Vector2 textSize = font.MeasureString (message);
-				Vector2 textPosition = (viewportSize - textSize) / 2;
-
-				Color color = Color.White * TransitionAlpha;
-
-				// Animate the number of dots after our "Loading..." message.
-				loadAnimationTimer += gameTime.ElapsedGameTime;
-
-				int dotCount = (int)(loadAnimationTimer.TotalSeconds * 5) % 10;
-
-				message += new string ('.', dotCount);
-
-				// Draw the text.
-				spriteBatch.Begin ();
-				spriteBatch.DrawString (font, message, textPosition, color);
-				spriteBatch.End ();
-			}
-		}
-
-
-	#endregion
-
-	#region Background Thread
-
-
-		/// <summary>
-		/// Worker thread draws the loading animation and updates the network
-		/// session while the load is taking place.
-		/// </summary>
-		void BackgroundWorkerThread ()
-		{
-			long lastTime = Stopwatch.GetTimestamp ();
-
-			// EventWaitHandle.WaitOne will return true if the exit signal has
-			// been triggered, or false if the timeout has expired. We use the
-			// timeout to update at regular intervals, then break out of the
-			// loop when we are signalled to exit.
-			while (!backgroundThreadExit.WaitOne (1000 / 30)) {
-				//GameTime gameTime = GetGameTime (ref lastTime);
-
-				//DrawLoadAnimation (gameTime);
-
-				UpdateNetworkSession ();
-			}
-		}
-
-
-//		/// <summary>
-//		/// Works out how long it has been since the last background thread update.
-//		/// </summary>
-//		GameTime GetGameTime (ref long lastTime)
-//		{
-//			long currentTime = Stopwatch.GetTimestamp ();
-//			long elapsedTicks = currentTime - lastTime;
-//			lastTime = currentTime;
-//
-//			TimeSpan elapsedTime = TimeSpan.FromTicks (elapsedTicks * 
-//						TimeSpan.TicksPerSecond / 
-//						Stopwatch.Frequency);
-//
-//			return new GameTime (loadStartTime.TotalGameTime + elapsedTime, elapsedTime);
-//		}
-
-
-		/// <summary>
-		/// Calls directly into our Draw method from the background worker thread,
-		/// so as to update the load animation in parallel with the actual loading.
-		/// </summary>
-		void DrawLoadAnimation (GameTime gameTime)
-		{
-			if ((graphicsDevice == null) || graphicsDevice.IsDisposed)
-				return;
-
-			try			{
-				graphicsDevice.Clear (Color.Black);
-
-				// Draw the loading screen.
-				Draw (gameTime);
-
-				// If we have a message display component, we want to display
-				// that over the top of the loading screen, too.
-				if (messageDisplay != null) {
-					messageDisplay.Update (gameTime);
-					messageDisplay.Draw (gameTime);
-				}
-
-				graphicsDevice.Present ();
-			} catch {
-				// If anything went wrong (for instance the graphics device was lost
-				// or reset) we don't have any good way to recover while running on a
-				// background thread. Setting the device to null will stop us from
-				// rendering, so the main game can deal with the problem later on.
-				graphicsDevice = null;
-			}
-		}
-
-
-		/// <summary>
-		/// Updates the network session from the background worker thread, to avoid
-		/// disconnecting due to network timeouts even if loading takes a long time.
-		/// </summary>
-		void UpdateNetworkSession ()
-		{
-			if ((networkSession == null) || 
-		(networkSession.SessionState == NetworkSessionState.Ended))
-				return;
-
-			try			{
-				networkSession.Update ();
-			} catch {
-				// If anything went wrong, we don't have a good way to report that
-				// error while running on a background thread. Setting the session to
-				// null will stop us from updating it, so the main game can deal with
-				// the problem later on.
-				networkSession = null;
-			}
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// LoadingScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Threading;
+using System.Diagnostics;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Net;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// The loading screen coordinates transitions between the menu system and the
+	/// game itself. Normally one screen will transition off at the same time as
+	/// the next screen is transitioning on, but for larger transitions that can
+	/// take a longer time to load their data, we want the menu system to be entirely
+	/// gone before we start loading the game. This is done as follows:
+	/// 
+	/// - Tell all the existing screens to transition off.
+	/// - Activate a loading screen, which will transition on at the same time.
+	/// - The loading screen watches the state of the previous screens.
+	/// - When it sees they have finished transitioning off, it activates the real
+	///   next screen, which may take a long time to load its data. The loading
+	///   screen will be the only thing displayed while this load is taking place.
+	/// </summary>
+	class LoadingScreen : GameScreen
+	{
+
+		bool loadingIsSlow;
+		bool otherScreensAreGone;
+		GameScreen[] screensToLoad;
+		Thread backgroundThread;
+		EventWaitHandle backgroundThreadExit;
+		GraphicsDevice graphicsDevice;
+		NetworkSession networkSession;
+		IMessageDisplay messageDisplay;
+		GameTime loadStartTime;
+		TimeSpan loadAnimationTimer;
+
+
+
+
+		/// <summary>
+		/// The constructor is private: loading screens should
+		/// be activated via the static Load method instead.
+		/// </summary>
+		private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
+				GameScreen[] screensToLoad)
+		{
+			this.loadingIsSlow = loadingIsSlow;
+			this.screensToLoad = screensToLoad;
+
+			TransitionOnTime = TimeSpan.FromSeconds(0.5);
+
+			// If this is going to be a slow load operation, create a background
+			// thread that will update the network session and draw the load screen
+			// animation while the load is taking place.
+			if (loadingIsSlow)
+			{
+				backgroundThread = new Thread(BackgroundWorkerThread);
+				backgroundThreadExit = new ManualResetEvent(false);
+
+				graphicsDevice = screenManager.GraphicsDevice;
+
+				// Look up some services that will be used by the background thread.
+				IServiceProvider services = screenManager.Game.Services;
+
+				networkSession = (NetworkSession)services.GetService(
+							typeof(NetworkSession));
+
+				messageDisplay = (IMessageDisplay)services.GetService(
+							typeof(IMessageDisplay));
+			}
+		}
+
+
+		/// <summary>
+		/// Activates the loading screen.
+		/// </summary>
+		public static void Load(ScreenManager screenManager, bool loadingIsSlow,
+				PlayerIndex? controllingPlayer,
+				params GameScreen[] screensToLoad)
+		{
+			// Tell all the current screens to transition off.
+			foreach (GameScreen screen in screenManager.GetScreens())
+				screen.ExitScreen();
+
+			// Create and activate the loading screen.
+			LoadingScreen loadingScreen = new LoadingScreen(screenManager,
+							loadingIsSlow,
+							screensToLoad);
+
+			screenManager.AddScreen(loadingScreen, controllingPlayer);
+		}
+
+
+
+
+
+		/// <summary>
+		/// Updates the loading screen.
+		/// </summary>
+		public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+							bool coveredByOtherScreen)
+		{
+			base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+			// If all the previous screens have finished transitioning
+			// off, it is time to actually perform the load.
+			if (otherScreensAreGone)
+			{
+				// Start up the background thread, which will update the network
+				// session and draw the animation while we are loading.
+				if (backgroundThread != null)
+				{
+					loadStartTime = gameTime;
+					backgroundThread.Start();
+				}
+
+				// Perform the load operation.
+				ScreenManager.RemoveScreen(this);
+
+				foreach (GameScreen screen in screensToLoad)
+				{
+					if (screen != null)
+					{
+						ScreenManager.AddScreen(screen, ControllingPlayer);
+					}
+				}
+
+				// Signal the background thread to exit, then wait for it to do so.
+				if (backgroundThread != null)
+				{
+					backgroundThreadExit.Set();
+					backgroundThread.Join();
+				}
+
+				// Once the load has finished, we use ResetElapsedTime to tell
+				// the  game timing mechanism that we have just finished a very
+				// long frame, and that it should not try to catch up.
+				ScreenManager.Game.ResetElapsedTime();
+			}
+		}
+
+
+		/// <summary>
+		/// Draws the loading screen.
+		/// </summary>
+		public override void Draw(GameTime gameTime)
+		{
+			// If we are the only active screen, that means all the previous screens
+			// must have finished transitioning off. We check for this in the Draw
+			// method, rather than in Update, because it isn't enough just for the
+			// screens to be gone: in order for the transition to look good we must
+			// have actually drawn a frame without them before we perform the load.
+			if ((ScreenState == ScreenState.Active) &&
+		(ScreenManager.GetScreens().Length == 1))
+			{
+				otherScreensAreGone = true;
+			}
+
+			// The gameplay screen takes a while to load, so we display a loading
+			// message while that is going on, but the menus load very quickly, and
+			// it would look silly if we flashed this up for just a fraction of a
+			// second while returning from the game to the menus. This parameter
+			// tells us how long the loading is going to take, so we know whether
+			// to bother drawing the message.
+			if (loadingIsSlow)
+			{
+				SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+				SpriteFont font = ScreenManager.Font;
+
+				string message = Resources.Loading;
+
+				// Center the text in the viewport.
+				Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+				Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+				Vector2 textSize = font.MeasureString(message);
+				Vector2 textPosition = (viewportSize - textSize) / 2;
+
+				Color color = Color.White * TransitionAlpha;
+
+				// Animate the number of dots after our "Loading..." message.
+				loadAnimationTimer += gameTime.ElapsedGameTime;
+
+				int dotCount = (int)(loadAnimationTimer.TotalSeconds * 5) % 10;
+
+				message += new string('.', dotCount);
+
+				// Draw the text.
+				spriteBatch.Begin();
+				spriteBatch.DrawString(font, message, textPosition, color);
+				spriteBatch.End();
+			}
+		}
+
+
+
+
+
+		/// <summary>
+		/// Worker thread draws the loading animation and updates the network
+		/// session while the load is taking place.
+		/// </summary>
+		void BackgroundWorkerThread()
+		{
+			long lastTime = Stopwatch.GetTimestamp();
+
+			// EventWaitHandle.WaitOne will return true if the exit signal has
+			// been triggered, or false if the timeout has expired. We use the
+			// timeout to update at regular intervals, then break out of the
+			// loop when we are signalled to exit.
+			while (!backgroundThreadExit.WaitOne(1000 / 30))
+			{
+				//GameTime gameTime = GetGameTime (ref lastTime);
+
+				//DrawLoadAnimation (gameTime);
+
+				UpdateNetworkSession();
+			}
+		}
+
+
+		//		/// <summary>
+		//		/// Works out how long it has been since the last background thread update.
+		//		/// </summary>
+		//		GameTime GetGameTime (ref long lastTime)
+		//		{
+		//			long currentTime = Stopwatch.GetTimestamp ();
+		//			long elapsedTicks = currentTime - lastTime;
+		//			lastTime = currentTime;
+		//
+		//			TimeSpan elapsedTime = TimeSpan.FromTicks (elapsedTicks * 
+		//						TimeSpan.TicksPerSecond / 
+		//						Stopwatch.Frequency);
+		//
+		//			return new GameTime (loadStartTime.TotalGameTime + elapsedTime, elapsedTime);
+		//		}
+
+
+		/// <summary>
+		/// Calls directly into our Draw method from the background worker thread,
+		/// so as to update the load animation in parallel with the actual loading.
+		/// </summary>
+		void DrawLoadAnimation(GameTime gameTime)
+		{
+			if ((graphicsDevice == null) || graphicsDevice.IsDisposed)
+				return;
+
+			try
+			{
+				graphicsDevice.Clear(Color.Black);
+
+				// Draw the loading screen.
+				Draw(gameTime);
+
+				// If we have a message display component, we want to display
+				// that over the top of the loading screen, too.
+				if (messageDisplay != null)
+				{
+					messageDisplay.Update(gameTime);
+					messageDisplay.Draw(gameTime);
+				}
+
+				graphicsDevice.Present();
+			}
+			catch
+			{
+				// If anything went wrong (for instance the graphics device was lost
+				// or reset) we don't have any good way to recover while running on a
+				// background thread. Setting the device to null will stop us from
+				// rendering, so the main game can deal with the problem later on.
+				graphicsDevice = null;
+			}
+		}
+
+
+		/// <summary>
+		/// Updates the network session from the background worker thread, to avoid
+		/// disconnecting due to network timeouts even if loading takes a long time.
+		/// </summary>
+		void UpdateNetworkSession()
+		{
+			if ((networkSession == null) ||
+		(networkSession.SessionState == NetworkSessionState.Ended))
+				return;
+
+			try
+			{
+				networkSession.Update();
+			}
+			catch
+			{
+				// If anything went wrong, we don't have a good way to report that
+				// error while running on a background thread. Setting the session to
+				// null will stop us from updating it, so the main game can deal with
+				// the problem later on.
+				networkSession = null;
+			}
+		}
+
+
+	}
+}

+ 126 - 134
NetworkStateManagement/Screens/MainMenuScreen.cs → NetworkStateManagement/Core/Screens/MainMenuScreen.cs

@@ -1,134 +1,126 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MainMenuScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// The main menu screen is the first thing displayed when the game starts up.
-	/// </summary>
-	class MainMenuScreen : MenuScreen
-	{
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructor fills in the menu contents.
-		/// </summary>
-		public MainMenuScreen ()
-		: base(Resources.MainMenu)
-			{
-			// Create our menu entries.
-			MenuEntry singlePlayerMenuEntry = new MenuEntry (Resources.SinglePlayer);
-			MenuEntry liveMenuEntry = new MenuEntry (Resources.PlayerMatch);
-			MenuEntry systemLinkMenuEntry = new MenuEntry (Resources.SystemLink);
-			MenuEntry exitMenuEntry = new MenuEntry (Resources.Exit);
-
-			// Hook up menu event handlers.
-			singlePlayerMenuEntry.Selected += SinglePlayerMenuEntrySelected;
-			liveMenuEntry.Selected += LiveMenuEntrySelected;
-			systemLinkMenuEntry.Selected += SystemLinkMenuEntrySelected;
-			exitMenuEntry.Selected += OnCancel;
-
-			// Add entries to the menu.
-			MenuEntries.Add (singlePlayerMenuEntry);
-			MenuEntries.Add (liveMenuEntry);
-			MenuEntries.Add (systemLinkMenuEntry);
-			MenuEntries.Add (exitMenuEntry);
-		}
-
-
-	#endregion
-
-	#region Handle Input
-
-
-		/// <summary>
-		/// Event handler for when the Single Player menu entry is selected.
-		/// </summary>
-		void SinglePlayerMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			LoadingScreen.Load (ScreenManager, true, e.PlayerIndex, 
-				new GameplayScreen (null));
-		}
-
-
-		/// <summary>
-		/// Event handler for when the Live menu entry is selected.
-		/// </summary>
-		void LiveMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			CreateOrFindSession (NetworkSessionType.PlayerMatch, e.PlayerIndex);
-		}
-
-
-		/// <summary>
-		/// Event handler for when the System Link menu entry is selected.
-		/// </summary>
-		void SystemLinkMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			CreateOrFindSession (NetworkSessionType.SystemLink, e.PlayerIndex);
-		}
-
-
-		/// <summary>
-		/// Helper method shared by the Live and System Link menu event handlers.
-		/// </summary>
-		void CreateOrFindSession (NetworkSessionType sessionType,
-				PlayerIndex playerIndex)
-		{
-			// First, we need to make sure a suitable gamer profile is signed in.
-			ProfileSignInScreen profileSignIn = new ProfileSignInScreen (sessionType);
-
-			// Hook up an event so once the ProfileSignInScreen is happy,
-			// it will activate the CreateOrFindSessionScreen.
-			profileSignIn.ProfileSignedIn += delegate
-		{
-		GameScreen createOrFind = new CreateOrFindSessionScreen (sessionType);
-
-		ScreenManager.AddScreen (createOrFind, playerIndex);
-		};
-
-			// Activate the ProfileSignInScreen.
-			ScreenManager.AddScreen (profileSignIn, playerIndex);
-		}
-
-
-		/// <summary>
-		/// When the user cancels the main menu, ask if they want to exit the sample.
-		/// </summary>
-		protected override void OnCancel (PlayerIndex playerIndex)
-		{
-			MessageBoxScreen confirmExitMessageBox = 
-				new MessageBoxScreen (Resources.ConfirmExitSample);
-
-			confirmExitMessageBox.Accepted += ConfirmExitMessageBoxAccepted;
-
-			ScreenManager.AddScreen (confirmExitMessageBox, playerIndex);
-		}
-
-
-		/// <summary>
-		/// Event handler for when the user selects ok on the "are you sure
-		/// you want to exit" message box.
-		/// </summary>
-		void ConfirmExitMessageBoxAccepted (object sender, PlayerIndexEventArgs e)
-		{
-			ScreenManager.Game.Exit ();
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// MainMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// The main menu screen is the first thing displayed when the game starts up.
+	/// </summary>
+	class MainMenuScreen : MenuScreen
+	{
+
+
+		/// <summary>
+		/// Constructor fills in the menu contents.
+		/// </summary>
+		public MainMenuScreen()
+		: base(Resources.MainMenu)
+		{
+			// Create our menu entries.
+			MenuEntry singlePlayerMenuEntry = new MenuEntry(Resources.SinglePlayer);
+			MenuEntry liveMenuEntry = new MenuEntry(Resources.PlayerMatch);
+			MenuEntry systemLinkMenuEntry = new MenuEntry(Resources.SystemLink);
+			MenuEntry exitMenuEntry = new MenuEntry(Resources.Exit);
+
+			// Hook up menu event handlers.
+			singlePlayerMenuEntry.Selected += SinglePlayerMenuEntrySelected;
+			liveMenuEntry.Selected += LiveMenuEntrySelected;
+			systemLinkMenuEntry.Selected += SystemLinkMenuEntrySelected;
+			exitMenuEntry.Selected += OnCancel;
+
+			// Add entries to the menu.
+			MenuEntries.Add(singlePlayerMenuEntry);
+			MenuEntries.Add(liveMenuEntry);
+			MenuEntries.Add(systemLinkMenuEntry);
+			MenuEntries.Add(exitMenuEntry);
+		}
+
+
+
+
+
+		/// <summary>
+		/// Event handler for when the Single Player menu entry is selected.
+		/// </summary>
+		void SinglePlayerMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
+				new GameplayScreen(null));
+		}
+
+
+		/// <summary>
+		/// Event handler for when the Live menu entry is selected.
+		/// </summary>
+		void LiveMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			CreateOrFindSession(NetworkSessionType.PlayerMatch, e.PlayerIndex);
+		}
+
+
+		/// <summary>
+		/// Event handler for when the System Link menu entry is selected.
+		/// </summary>
+		void SystemLinkMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			CreateOrFindSession(NetworkSessionType.SystemLink, e.PlayerIndex);
+		}
+
+
+		/// <summary>
+		/// Helper method shared by the Live and System Link menu event handlers.
+		/// </summary>
+		void CreateOrFindSession(NetworkSessionType sessionType,
+				PlayerIndex playerIndex)
+		{
+			// First, we need to make sure a suitable gamer profile is signed in.
+			ProfileSignInScreen profileSignIn = new ProfileSignInScreen(sessionType);
+
+			// Hook up an event so once the ProfileSignInScreen is happy,
+			// it will activate the CreateOrFindSessionScreen.
+			profileSignIn.ProfileSignedIn += delegate
+		{
+			GameScreen createOrFind = new CreateOrFindSessionScreen(sessionType);
+
+			ScreenManager.AddScreen(createOrFind, playerIndex);
+		};
+
+			// Activate the ProfileSignInScreen.
+			ScreenManager.AddScreen(profileSignIn, playerIndex);
+		}
+
+
+		/// <summary>
+		/// When the user cancels the main menu, ask if they want to exit the sample.
+		/// </summary>
+		protected override void OnCancel(PlayerIndex playerIndex)
+		{
+			MessageBoxScreen confirmExitMessageBox =
+				new MessageBoxScreen(Resources.ConfirmExitSample);
+
+			confirmExitMessageBox.Accepted += ConfirmExitMessageBoxAccepted;
+
+			ScreenManager.AddScreen(confirmExitMessageBox, playerIndex);
+		}
+
+
+		/// <summary>
+		/// Event handler for when the user selects ok on the "are you sure
+		/// you want to exit" message box.
+		/// </summary>
+		void ConfirmExitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+		{
+			ScreenManager.Game.Exit();
+		}
+
+
+	}
+}

+ 175 - 191
NetworkStateManagement/Screens/MenuEntry.cs → NetworkStateManagement/Core/Screens/MenuEntry.cs

@@ -1,191 +1,175 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MenuEntry.cs
-//
-// XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Helper class represents a single entry in a MenuScreen. By default this
-    /// just draws the entry text string, but it can be customized to display menu
-    /// entries in different ways. This also provides an event that will be raised
-    /// when the menu entry is selected.
-    /// </summary>
-    class MenuEntry
-    {
-        #region Fields
-
-        /// <summary>
-        /// The text rendered for this entry.
-        /// </summary>
-        string text;
-
-        /// <summary>
-        /// Tracks a fading selection effect on the entry.
-        /// </summary>
-        /// <remarks>
-        /// The entries transition out of the selection effect when they are deselected.
-        /// </remarks>
-        float selectionFade;
-
-        /// <summary>
-        /// The position at which the entry is drawn. This is set by the MenuScreen
-        /// each frame in Update.
-        /// </summary>
-        Vector2 position;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// Gets or sets the text of this menu entry.
-        /// </summary>
-        public string Text
-        {
-            get { return text; }
-            set { text = value; }
-        }
-
-
-        /// <summary>
-        /// Gets or sets the position at which to draw this menu entry.
-        /// </summary>
-        public Vector2 Position
-        {
-            get { return position; }
-            set { position = value; }
-        }
-
-
-        #endregion
-
-        #region Events
-
-
-        /// <summary>
-        /// Event raised when the menu entry is selected.
-        /// </summary>
-        public event EventHandler<PlayerIndexEventArgs> Selected;
-
-
-        /// <summary>
-        /// Method for raising the Selected event.
-        /// </summary>
-        protected internal virtual void OnSelectEntry(PlayerIndex playerIndex)
-        {
-            if (Selected != null)
-                Selected(this, new PlayerIndexEventArgs(playerIndex));
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructs a new menu entry with the specified text.
-        /// </summary>
-        public MenuEntry(string text)
-        {
-            this.text = text;
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Updates the menu entry.
-        /// </summary>
-        public virtual void Update(MenuScreen screen, bool isSelected, GameTime gameTime)
-        {
-            // there is no such thing as a selected item on Windows Phone, so we always
-            // force isSelected to be false
-#if WINDOWS_PHONE
-            isSelected = false;
-#endif
-
-            // When the menu selection changes, entries gradually fade between
-            // their selected and deselected appearance, rather than instantly
-            // popping to the new state.
-            float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;
-
-            if (isSelected)
-                selectionFade = Math.Min(selectionFade + fadeSpeed, 1);
-            else
-                selectionFade = Math.Max(selectionFade - fadeSpeed, 0);
-        }
-
-
-        /// <summary>
-        /// Draws the menu entry. This can be overridden to customize the appearance.
-        /// </summary>
-        public virtual void Draw(MenuScreen screen, bool isSelected, GameTime gameTime)
-        {
-            // there is no such thing as a selected item on Windows Phone, so we always
-            // force isSelected to be false
-#if WINDOWS_PHONE
-            isSelected = false;
-#endif
-
-            // Draw the selected entry in yellow, otherwise white.
-            Color color = isSelected ? Color.Yellow : Color.White;
-
-            // Pulsate the size of the selected menu entry.
-            double time = gameTime.TotalGameTime.TotalSeconds;
-            
-            float pulsate = (float)Math.Sin(time * 6) + 1;
-
-            float scale = 1 + pulsate * 0.05f * selectionFade;
-
-            // Modify the alpha to fade text out during transitions.
-            color *= screen.TransitionAlpha;
-
-            // Draw text, centered on the middle of each line.
-            ScreenManager screenManager = screen.ScreenManager;
-            SpriteBatch spriteBatch = screenManager.SpriteBatch;
-            SpriteFont font = screenManager.Font;
-
-            Vector2 origin = new Vector2(0, font.LineSpacing / 2);
-
-            spriteBatch.DrawString(font, text, position, color, 0,
-                                   origin, scale, SpriteEffects.None, 0);
-        }
-
-
-        /// <summary>
-        /// Queries how much space this menu entry requires.
-        /// </summary>
-        public virtual int GetHeight(MenuScreen screen)
-        {
-            return screen.ScreenManager.Font.LineSpacing;
-        }
-
-
-        /// <summary>
-        /// Queries how wide the entry is, used for centering on the screen.
-        /// </summary>
-        public virtual int GetWidth(MenuScreen screen)
-        {
-            return (int)screen.ScreenManager.Font.MeasureString(Text).X;
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MenuEntry.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Helper class represents a single entry in a MenuScreen. By default this
+    /// just draws the entry text string, but it can be customized to display menu
+    /// entries in different ways. This also provides an event that will be raised
+    /// when the menu entry is selected.
+    /// </summary>
+    class MenuEntry
+    {
+
+        /// <summary>
+        /// The text rendered for this entry.
+        /// </summary>
+        string text;
+
+        /// <summary>
+        /// Tracks a fading selection effect on the entry.
+        /// </summary>
+        /// <remarks>
+        /// The entries transition out of the selection effect when they are deselected.
+        /// </remarks>
+        float selectionFade;
+
+        /// <summary>
+        /// The position at which the entry is drawn. This is set by the MenuScreen
+        /// each frame in Update.
+        /// </summary>
+        Vector2 position;
+
+
+
+
+        /// <summary>
+        /// Gets or sets the text of this menu entry.
+        /// </summary>
+        public string Text
+        {
+            get { return text; }
+            set { text = value; }
+        }
+
+
+        /// <summary>
+        /// Gets or sets the position at which to draw this menu entry.
+        /// </summary>
+        public Vector2 Position
+        {
+            get { return position; }
+            set { position = value; }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Event raised when the menu entry is selected.
+        /// </summary>
+        public event EventHandler<PlayerIndexEventArgs> Selected;
+
+
+        /// <summary>
+        /// Method for raising the Selected event.
+        /// </summary>
+        protected internal virtual void OnSelectEntry(PlayerIndex playerIndex)
+        {
+            if (Selected != null)
+                Selected(this, new PlayerIndexEventArgs(playerIndex));
+        }
+
+
+
+
+
+        /// <summary>
+        /// Constructs a new menu entry with the specified text.
+        /// </summary>
+        public MenuEntry(string text)
+        {
+            this.text = text;
+        }
+
+
+
+
+
+        /// <summary>
+        /// Updates the menu entry.
+        /// </summary>
+        public virtual void Update(MenuScreen screen, bool isSelected, GameTime gameTime)
+        {
+            // there is no such thing as a selected item on Windows Phone, so we always
+            // force isSelected to be false
+#if WINDOWS_PHONE
+            isSelected = false;
+#endif
+
+            // When the menu selection changes, entries gradually fade between
+            // their selected and deselected appearance, rather than instantly
+            // popping to the new state.
+            float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;
+
+            if (isSelected)
+                selectionFade = Math.Min(selectionFade + fadeSpeed, 1);
+            else
+                selectionFade = Math.Max(selectionFade - fadeSpeed, 0);
+        }
+
+
+        /// <summary>
+        /// Draws the menu entry. This can be overridden to customize the appearance.
+        /// </summary>
+        public virtual void Draw(MenuScreen screen, bool isSelected, GameTime gameTime)
+        {
+            // there is no such thing as a selected item on Windows Phone, so we always
+            // force isSelected to be false
+#if WINDOWS_PHONE
+            isSelected = false;
+#endif
+
+            // Draw the selected entry in yellow, otherwise white.
+            Color color = isSelected ? Color.Yellow : Color.White;
+
+            // Pulsate the size of the selected menu entry.
+            double time = gameTime.TotalGameTime.TotalSeconds;
+
+            float pulsate = (float)Math.Sin(time * 6) + 1;
+
+            float scale = 1 + pulsate * 0.05f * selectionFade;
+
+            // Modify the alpha to fade text out during transitions.
+            color *= screen.TransitionAlpha;
+
+            // Draw text, centered on the middle of each line.
+            ScreenManager screenManager = screen.ScreenManager;
+            SpriteBatch spriteBatch = screenManager.SpriteBatch;
+            SpriteFont font = screenManager.Font;
+
+            Vector2 origin = new Vector2(0, font.LineSpacing / 2);
+
+            spriteBatch.DrawString(font, text, position, color, 0,
+                                   origin, scale, SpriteEffects.None, 0);
+        }
+
+
+        /// <summary>
+        /// Queries how much space this menu entry requires.
+        /// </summary>
+        public virtual int GetHeight(MenuScreen screen)
+        {
+            return screen.ScreenManager.Font.LineSpacing;
+        }
+
+
+        /// <summary>
+        /// Queries how wide the entry is, used for centering on the screen.
+        /// </summary>
+        public virtual int GetWidth(MenuScreen screen)
+        {
+            return (int)screen.ScreenManager.Font.MeasureString(Text).X;
+        }
+    }
+}

+ 230 - 244
NetworkStateManagement/Screens/MenuScreen.cs → NetworkStateManagement/Core/Screens/MenuScreen.cs

@@ -1,244 +1,230 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MenuScreen.cs
-//
-// XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework.Input.Touch;
-using Microsoft.Xna.Framework.Input;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Base class for screens that contain a menu of options. The user can
-    /// move up and down to select an entry, or cancel to back out of the screen.
-    /// </summary>
-    abstract class MenuScreen : GameScreen
-    {
-        #region Fields
-
-        List<MenuEntry> menuEntries = new List<MenuEntry>();
-        int selectedEntry = 0;
-        string menuTitle;
-
-        #endregion
-
-        #region Properties
-
-
-        /// <summary>
-        /// Gets the list of menu entries, so derived classes can add
-        /// or change the menu contents.
-        /// </summary>
-        protected IList<MenuEntry> MenuEntries
-        {
-            get { return menuEntries; }
-        }
-
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public MenuScreen(string menuTitle)
-        {
-            this.menuTitle = menuTitle;
-
-            TransitionOnTime = TimeSpan.FromSeconds(0.5);
-            TransitionOffTime = TimeSpan.FromSeconds(0.5);
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Responds to user input, changing the selected entry and accepting
-        /// or cancelling the menu.
-        /// </summary>
-        public override void HandleInput(InputState input)
-        {
-            // Move to the previous menu entry?
-            if (input.IsMenuUp(ControllingPlayer))
-            {
-                selectedEntry--;
-
-                if (selectedEntry < 0)
-                    selectedEntry = menuEntries.Count - 1;
-            }
-
-            // Move to the next menu entry?
-            if (input.IsMenuDown(ControllingPlayer))
-            {
-                selectedEntry++;
-
-                if (selectedEntry >= menuEntries.Count)
-                    selectedEntry = 0;
-            }
-
-            // Accept or cancel the menu? We pass in our ControllingPlayer, which may
-            // either be null (to accept input from any player) or a specific index.
-            // If we pass a null controlling player, the InputState helper returns to
-            // us which player actually provided the input. We pass that through to
-            // OnSelectEntry and OnCancel, so they can tell which player triggered them.
-            PlayerIndex playerIndex;
-
-            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
-            {
-                OnSelectEntry(selectedEntry, playerIndex);
-            }
-            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
-            {
-                OnCancel(playerIndex);
-            }
-        }
-
-
-        /// <summary>
-        /// Handler for when the user has chosen a menu entry.
-        /// </summary>
-        protected virtual void OnSelectEntry(int entryIndex, PlayerIndex playerIndex)
-        {
-            menuEntries[entryIndex].OnSelectEntry(playerIndex);
-        }
-
-
-        /// <summary>
-        /// Handler for when the user has cancelled the menu.
-        /// </summary>
-        protected virtual void OnCancel(PlayerIndex playerIndex)
-        {
-            ExitScreen();
-        }
-
-
-        /// <summary>
-        /// Helper overload makes it easy to use OnCancel as a MenuEntry event handler.
-        /// </summary>
-        protected void OnCancel(object sender, PlayerIndexEventArgs e)
-        {
-            OnCancel(e.PlayerIndex);
-        }
-
-
-        #endregion
-
-        #region Update and Draw
-
-
-        /// <summary>
-        /// Allows the screen the chance to position the menu entries. By default
-        /// all menu entries are lined up in a vertical list, centered on the screen.
-        /// </summary>
-        protected virtual void UpdateMenuEntryLocations()
-        {
-            // Make the menu slide into place during transitions, using a
-            // power curve to make things look more interesting (this makes
-            // the movement slow down as it nears the end).
-            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
-
-            // start at Y = 175; each X value is generated per entry
-            Vector2 position = new Vector2(0f, 175f);
-
-            // update each menu entry's location in turn
-            for (int i = 0; i < menuEntries.Count; i++)
-            {
-                MenuEntry menuEntry = menuEntries[i];
-                
-                // each entry is to be centered horizontally
-                position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;
-
-                if (ScreenState == ScreenState.TransitionOn)
-                    position.X -= transitionOffset * 256;
-                else
-                    position.X += transitionOffset * 512;
-
-                // set the entry's position
-                menuEntry.Position = position;
-
-                // move down for the next entry the size of this entry
-                position.Y += menuEntry.GetHeight(this);
-            }
-        }
-
-
-        /// <summary>
-        /// Updates the menu.
-        /// </summary>
-        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
-                                                       bool coveredByOtherScreen)
-        {
-            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
-
-            // Update each nested MenuEntry object.
-            for (int i = 0; i < menuEntries.Count; i++)
-            {
-                bool isSelected = IsActive && (i == selectedEntry);
-
-                menuEntries[i].Update(this, isSelected, gameTime);
-            }
-        }
-
-
-        /// <summary>
-        /// Draws the menu.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            // make sure our entries are in the right place before we draw them
-            UpdateMenuEntryLocations();
-
-            GraphicsDevice graphics = ScreenManager.GraphicsDevice;
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-            SpriteFont font = ScreenManager.Font;
-
-            spriteBatch.Begin();
-
-            // Draw each menu entry in turn.
-            for (int i = 0; i < menuEntries.Count; i++)
-            {
-                MenuEntry menuEntry = menuEntries[i];
-
-                bool isSelected = IsActive && (i == selectedEntry);
-
-                menuEntry.Draw(this, isSelected, gameTime);
-            }
-
-            // Make the menu slide into place during transitions, using a
-            // power curve to make things look more interesting (this makes
-            // the movement slow down as it nears the end).
-            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
-
-            // Draw the menu title centered on the screen
-            Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
-            Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
-            Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
-            float titleScale = 1.25f;
-
-            titlePosition.Y -= transitionOffset * 100;
-
-            spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
-                                   titleOrigin, titleScale, SpriteEffects.None, 0);
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MenuScreen.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input.Touch;
+using Microsoft.Xna.Framework.Input;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Base class for screens that contain a menu of options. The user can
+    /// move up and down to select an entry, or cancel to back out of the screen.
+    /// </summary>
+    abstract class MenuScreen : GameScreen
+    {
+
+        List<MenuEntry> menuEntries = new List<MenuEntry>();
+        int selectedEntry = 0;
+        string menuTitle;
+
+
+
+
+        /// <summary>
+        /// Gets the list of menu entries, so derived classes can add
+        /// or change the menu contents.
+        /// </summary>
+        protected IList<MenuEntry> MenuEntries
+        {
+            get { return menuEntries; }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public MenuScreen(string menuTitle)
+        {
+            this.menuTitle = menuTitle;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.5);
+            TransitionOffTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Responds to user input, changing the selected entry and accepting
+        /// or cancelling the menu.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            // Move to the previous menu entry?
+            if (input.IsMenuUp(ControllingPlayer))
+            {
+                selectedEntry--;
+
+                if (selectedEntry < 0)
+                    selectedEntry = menuEntries.Count - 1;
+            }
+
+            // Move to the next menu entry?
+            if (input.IsMenuDown(ControllingPlayer))
+            {
+                selectedEntry++;
+
+                if (selectedEntry >= menuEntries.Count)
+                    selectedEntry = 0;
+            }
+
+            // Accept or cancel the menu? We pass in our ControllingPlayer, which may
+            // either be null (to accept input from any player) or a specific index.
+            // If we pass a null controlling player, the InputState helper returns to
+            // us which player actually provided the input. We pass that through to
+            // OnSelectEntry and OnCancel, so they can tell which player triggered them.
+            PlayerIndex playerIndex;
+
+            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
+            {
+                OnSelectEntry(selectedEntry, playerIndex);
+            }
+            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
+            {
+                OnCancel(playerIndex);
+            }
+        }
+
+
+        /// <summary>
+        /// Handler for when the user has chosen a menu entry.
+        /// </summary>
+        protected virtual void OnSelectEntry(int entryIndex, PlayerIndex playerIndex)
+        {
+            menuEntries[entryIndex].OnSelectEntry(playerIndex);
+        }
+
+
+        /// <summary>
+        /// Handler for when the user has cancelled the menu.
+        /// </summary>
+        protected virtual void OnCancel(PlayerIndex playerIndex)
+        {
+            ExitScreen();
+        }
+
+
+        /// <summary>
+        /// Helper overload makes it easy to use OnCancel as a MenuEntry event handler.
+        /// </summary>
+        protected void OnCancel(object sender, PlayerIndexEventArgs e)
+        {
+            OnCancel(e.PlayerIndex);
+        }
+
+
+
+
+
+        /// <summary>
+        /// Allows the screen the chance to position the menu entries. By default
+        /// all menu entries are lined up in a vertical list, centered on the screen.
+        /// </summary>
+        protected virtual void UpdateMenuEntryLocations()
+        {
+            // Make the menu slide into place during transitions, using a
+            // power curve to make things look more interesting (this makes
+            // the movement slow down as it nears the end).
+            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+            // start at Y = 175; each X value is generated per entry
+            Vector2 position = new Vector2(0f, 175f);
+
+            // update each menu entry's location in turn
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                MenuEntry menuEntry = menuEntries[i];
+
+                // each entry is to be centered horizontally
+                position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth(this) / 2;
+
+                if (ScreenState == ScreenState.TransitionOn)
+                    position.X -= transitionOffset * 256;
+                else
+                    position.X += transitionOffset * 512;
+
+                // set the entry's position
+                menuEntry.Position = position;
+
+                // move down for the next entry the size of this entry
+                position.Y += menuEntry.GetHeight(this);
+            }
+        }
+
+
+        /// <summary>
+        /// Updates the menu.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            // Update each nested MenuEntry object.
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                bool isSelected = IsActive && (i == selectedEntry);
+
+                menuEntries[i].Update(this, isSelected, gameTime);
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the menu.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // make sure our entries are in the right place before we draw them
+            UpdateMenuEntryLocations();
+
+            GraphicsDevice graphics = ScreenManager.GraphicsDevice;
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            SpriteFont font = ScreenManager.Font;
+
+            spriteBatch.Begin();
+
+            // Draw each menu entry in turn.
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                MenuEntry menuEntry = menuEntries[i];
+
+                bool isSelected = IsActive && (i == selectedEntry);
+
+                menuEntry.Draw(this, isSelected, gameTime);
+            }
+
+            // Make the menu slide into place during transitions, using a
+            // power curve to make things look more interesting (this makes
+            // the movement slow down as it nears the end).
+            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+            // Draw the menu title centered on the screen
+            Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
+            Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
+            Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
+            float titleScale = 1.25f;
+
+            titlePosition.Y -= transitionOffset * 100;
+
+            spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
+                                   titleOrigin, titleScale, SpriteEffects.None, 0);
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 153 - 167
NetworkStateManagement/Screens/MessageBoxScreen.cs → NetworkStateManagement/Core/Screens/MessageBoxScreen.cs

@@ -1,167 +1,153 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// MessageBoxScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Content;
-using Microsoft.Xna.Framework.Graphics;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// A popup message box screen, used to display "are you sure?"
-    /// confirmation messages.
-    /// </summary>
-    class MessageBoxScreen : GameScreen
-    {
-        #region Fields
-
-        string message;
-        Texture2D gradientTexture;
-
-        #endregion
-
-        #region Events
-
-        public event EventHandler<PlayerIndexEventArgs> Accepted;
-        public event EventHandler<PlayerIndexEventArgs> Cancelled;
-
-        #endregion
-
-        #region Initialization
-
-
-        /// <summary>
-        /// Constructor automatically includes the standard "A=ok, B=cancel"
-        /// usage text prompt.
-        /// </summary>
-        public MessageBoxScreen(string message)
-            : this(message, true)
-        { }
-
-
-        /// <summary>
-        /// Constructor lets the caller specify whether to include the standard
-        /// "A=ok, B=cancel" usage text prompt.
-        /// </summary>
-        public MessageBoxScreen(string message, bool includeUsageText)
-        {
-            if (includeUsageText)
-                this.message = message + Resources.MessageBoxUsage;
-            else
-                this.message = message;
-
-            IsPopup = true;
-
-            TransitionOnTime = TimeSpan.FromSeconds(0.2);
-            TransitionOffTime = TimeSpan.FromSeconds(0.2);
-        }
-
-
-        /// <summary>
-        /// Loads graphics content for this screen. This uses the shared ContentManager
-        /// provided by the Game class, so the content will remain loaded forever.
-        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
-        /// it will just get back another reference to the already loaded data.
-        /// </summary>
-        public override void LoadContent()
-        {
-            ContentManager content = ScreenManager.Game.Content;
-
-            gradientTexture = content.Load<Texture2D>("gradient");
-        }
-
-
-        #endregion
-
-        #region Handle Input
-
-
-        /// <summary>
-        /// Responds to user input, accepting or cancelling the message box.
-        /// </summary>
-        public override void HandleInput(InputState input)
-        {
-            PlayerIndex playerIndex;
-
-            // We pass in our ControllingPlayer, which may either be null (to
-            // accept input from any player) or a specific index. If we pass a null
-            // controlling player, the InputState helper returns to us which player
-            // actually provided the input. We pass that through to our Accepted and
-            // Cancelled events, so they can tell which player triggered them.
-            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
-            {
-                // Raise the accepted event, then exit the message box.
-                if (Accepted != null)
-                    Accepted(this, new PlayerIndexEventArgs(playerIndex));
-
-                ExitScreen();
-            }
-            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
-            {
-                // Raise the cancelled event, then exit the message box.
-                if (Cancelled != null)
-                    Cancelled(this, new PlayerIndexEventArgs(playerIndex));
-
-                ExitScreen();
-            }
-        }
-
-
-        #endregion
-
-        #region Draw
-
-
-        /// <summary>
-        /// Draws the message box.
-        /// </summary>
-        public override void Draw(GameTime gameTime)
-        {
-            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
-            SpriteFont font = ScreenManager.Font;
-
-            // Darken down any other screens that were drawn beneath the popup.
-            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);
-
-            // Center the message text in the viewport.
-            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
-            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
-            Vector2 textSize = font.MeasureString(message);
-            Vector2 textPosition = (viewportSize - textSize) / 2;
-
-            // The background includes a border somewhat larger than the text itself.
-            const int hPad = 32;
-            const int vPad = 16;
-
-            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
-                                                          (int)textPosition.Y - vPad,
-                                                          (int)textSize.X + hPad * 2,
-                                                          (int)textSize.Y + vPad * 2);
-
-            // Fade the popup alpha during transitions.
-            Color color = Color.White * TransitionAlpha;
-
-            spriteBatch.Begin();
-
-            // Draw the background rectangle.
-            spriteBatch.Draw(gradientTexture, backgroundRectangle, color);
-
-            // Draw the message box text.
-            spriteBatch.DrawString(font, message, textPosition, color);
-
-            spriteBatch.End();
-        }
-
-
-        #endregion
-    }
-}
+//-----------------------------------------------------------------------------
+// MessageBoxScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// A popup message box screen, used to display "are you sure?"
+    /// confirmation messages.
+    /// </summary>
+    class MessageBoxScreen : GameScreen
+    {
+
+        string message;
+        Texture2D gradientTexture;
+
+
+
+        public event EventHandler<PlayerIndexEventArgs> Accepted;
+        public event EventHandler<PlayerIndexEventArgs> Cancelled;
+
+
+
+
+        /// <summary>
+        /// Constructor automatically includes the standard "A=ok, B=cancel"
+        /// usage text prompt.
+        /// </summary>
+        public MessageBoxScreen(string message)
+            : this(message, true)
+        { }
+
+
+        /// <summary>
+        /// Constructor lets the caller specify whether to include the standard
+        /// "A=ok, B=cancel" usage text prompt.
+        /// </summary>
+        public MessageBoxScreen(string message, bool includeUsageText)
+        {
+            if (includeUsageText)
+                this.message = message + Resources.MessageBoxUsage;
+            else
+                this.message = message;
+
+            IsPopup = true;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.2);
+            TransitionOffTime = TimeSpan.FromSeconds(0.2);
+        }
+
+
+        /// <summary>
+        /// Loads graphics content for this screen. This uses the shared ContentManager
+        /// provided by the Game class, so the content will remain loaded forever.
+        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
+        /// it will just get back another reference to the already loaded data.
+        /// </summary>
+        public override void LoadContent()
+        {
+            ContentManager content = ScreenManager.Game.Content;
+
+            gradientTexture = content.Load<Texture2D>("gradient");
+        }
+
+
+
+
+
+        /// <summary>
+        /// Responds to user input, accepting or cancelling the message box.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            PlayerIndex playerIndex;
+
+            // We pass in our ControllingPlayer, which may either be null (to
+            // accept input from any player) or a specific index. If we pass a null
+            // controlling player, the InputState helper returns to us which player
+            // actually provided the input. We pass that through to our Accepted and
+            // Cancelled events, so they can tell which player triggered them.
+            if (input.IsMenuSelect(ControllingPlayer, out playerIndex))
+            {
+                // Raise the accepted event, then exit the message box.
+                if (Accepted != null)
+                    Accepted(this, new PlayerIndexEventArgs(playerIndex));
+
+                ExitScreen();
+            }
+            else if (input.IsMenuCancel(ControllingPlayer, out playerIndex))
+            {
+                // Raise the cancelled event, then exit the message box.
+                if (Cancelled != null)
+                    Cancelled(this, new PlayerIndexEventArgs(playerIndex));
+
+                ExitScreen();
+            }
+        }
+
+
+
+
+
+        /// <summary>
+        /// Draws the message box.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            SpriteFont font = ScreenManager.Font;
+
+            // Darken down any other screens that were drawn beneath the popup.
+            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);
+
+            // Center the message text in the viewport.
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+            Vector2 textSize = font.MeasureString(message);
+            Vector2 textPosition = (viewportSize - textSize) / 2;
+
+            // The background includes a border somewhat larger than the text itself.
+            const int hPad = 32;
+            const int vPad = 16;
+
+            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
+                                                          (int)textPosition.Y - vPad,
+                                                          (int)textSize.X + hPad * 2,
+                                                          (int)textSize.Y + vPad * 2);
+
+            // Fade the popup alpha during transitions.
+            Color color = Color.White * TransitionAlpha;
+
+            spriteBatch.Begin();
+
+            // Draw the background rectangle.
+            spriteBatch.Draw(gradientTexture, backgroundRectangle, color);
+
+            // Draw the message box text.
+            spriteBatch.DrawString(font, message, textPosition, color);
+
+            spriteBatch.End();
+        }
+
+
+    }
+}

+ 118 - 123
NetworkStateManagement/Screens/PauseMenuScreen.cs → NetworkStateManagement/Core/Screens/PauseMenuScreen.cs

@@ -1,123 +1,118 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// PauseMenuScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// The pause menu comes up over the top of the game,
-	/// giving the player options to resume or quit.
-	/// </summary>
-	class PauseMenuScreen : MenuScreen
-	{
-	#region Fields
-
-		NetworkSession networkSession;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructor.
-		/// </summary>
-		public PauseMenuScreen (NetworkSession networkSession)
-		: base(Resources.Paused)
-			{
-			this.networkSession = networkSession;
-
-			// Add the Resume Game menu entry.
-			MenuEntry resumeGameMenuEntry = new MenuEntry (Resources.ResumeGame);
-			resumeGameMenuEntry.Selected += OnCancel;
-			MenuEntries.Add (resumeGameMenuEntry);
-
-			if (networkSession == null) {
-				// If this is a single player game, add the Quit menu entry.
-				MenuEntry quitGameMenuEntry = new MenuEntry (Resources.QuitGame);
-				quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
-				MenuEntries.Add (quitGameMenuEntry);
-			} else {
-				// If we are hosting a network game, add the Return to Lobby menu entry.
-				if (networkSession.IsHost) {
-					MenuEntry lobbyMenuEntry = new MenuEntry (Resources.ReturnToLobby);
-					lobbyMenuEntry.Selected += ReturnToLobbyMenuEntrySelected;
-					MenuEntries.Add (lobbyMenuEntry);
-				}
-
-				// Add the End/Leave Session menu entry.
-				string leaveEntryText = networkSession.IsHost ? Resources.EndSession : 
-								Resources.LeaveSession;
-
-				MenuEntry leaveSessionMenuEntry = new MenuEntry (leaveEntryText);
-				leaveSessionMenuEntry.Selected += LeaveSessionMenuEntrySelected;
-				MenuEntries.Add (leaveSessionMenuEntry);
-			}
-		}
-
-
-	#endregion
-
-	#region Handle Input
-
-
-		/// <summary>
-		/// Event handler for when the Quit Game menu entry is selected.
-		/// </summary>
-		void QuitGameMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			MessageBoxScreen confirmQuitMessageBox = 
-				new MessageBoxScreen (Resources.ConfirmQuitGame);
-
-			confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;
-
-			ScreenManager.AddScreen (confirmQuitMessageBox, ControllingPlayer);
-		}
-
-
-		/// <summary>
-		/// Event handler for when the user selects ok on the "are you sure
-		/// you want to quit" message box. This uses the loading screen to
-		/// transition from the game back to the main menu screen.
-		/// </summary>
-		void ConfirmQuitMessageBoxAccepted (object sender, PlayerIndexEventArgs e)
-		{
-			LoadingScreen.Load (ScreenManager, false, null, new BackgroundScreen (), 
-							new MainMenuScreen ());
-		}
-
-
-		/// <summary>
-		/// Event handler for when the Return to Lobby menu entry is selected.
-		/// </summary>
-		void ReturnToLobbyMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			if (networkSession.SessionState == NetworkSessionState.Playing) {
-				networkSession.EndGame ();
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the End/Leave Session menu entry is selected.
-		/// </summary>
-		void LeaveSessionMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			NetworkSessionComponent.LeaveSession (ScreenManager, e.PlayerIndex);
-		}
-
-
-	#endregion
-	}
-}
+//-----------------------------------------------------------------------------
+// PauseMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Net;
+
+
+namespace NetworkStateManagement
+{
+	/// <summary>
+	/// The pause menu comes up over the top of the game,
+	/// giving the player options to resume or quit.
+	/// </summary>
+	class PauseMenuScreen : MenuScreen
+	{
+
+		NetworkSession networkSession;
+
+
+
+
+		/// <summary>
+		/// Constructor.
+		/// </summary>
+		public PauseMenuScreen(NetworkSession networkSession)
+		: base(Resources.Paused)
+		{
+			this.networkSession = networkSession;
+
+			// Add the Resume Game menu entry.
+			MenuEntry resumeGameMenuEntry = new MenuEntry(Resources.ResumeGame);
+			resumeGameMenuEntry.Selected += OnCancel;
+			MenuEntries.Add(resumeGameMenuEntry);
+
+			if (networkSession == null)
+			{
+				// If this is a single player game, add the Quit menu entry.
+				MenuEntry quitGameMenuEntry = new MenuEntry(Resources.QuitGame);
+				quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
+				MenuEntries.Add(quitGameMenuEntry);
+			}
+			else
+			{
+				// If we are hosting a network game, add the Return to Lobby menu entry.
+				if (networkSession.IsHost)
+				{
+					MenuEntry lobbyMenuEntry = new MenuEntry(Resources.ReturnToLobby);
+					lobbyMenuEntry.Selected += ReturnToLobbyMenuEntrySelected;
+					MenuEntries.Add(lobbyMenuEntry);
+				}
+
+				// Add the End/Leave Session menu entry.
+				string leaveEntryText = networkSession.IsHost ? Resources.EndSession :
+								Resources.LeaveSession;
+
+				MenuEntry leaveSessionMenuEntry = new MenuEntry(leaveEntryText);
+				leaveSessionMenuEntry.Selected += LeaveSessionMenuEntrySelected;
+				MenuEntries.Add(leaveSessionMenuEntry);
+			}
+		}
+
+
+
+
+
+		/// <summary>
+		/// Event handler for when the Quit Game menu entry is selected.
+		/// </summary>
+		void QuitGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			MessageBoxScreen confirmQuitMessageBox =
+				new MessageBoxScreen(Resources.ConfirmQuitGame);
+
+			confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;
+
+			ScreenManager.AddScreen(confirmQuitMessageBox, ControllingPlayer);
+		}
+
+
+		/// <summary>
+		/// Event handler for when the user selects ok on the "are you sure
+		/// you want to quit" message box. This uses the loading screen to
+		/// transition from the game back to the main menu screen.
+		/// </summary>
+		void ConfirmQuitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
+		{
+			LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
+							new MainMenuScreen());
+		}
+
+
+		/// <summary>
+		/// Event handler for when the Return to Lobby menu entry is selected.
+		/// </summary>
+		void ReturnToLobbyMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			if (networkSession.SessionState == NetworkSessionState.Playing)
+			{
+				networkSession.EndGame();
+			}
+		}
+
+
+		/// <summary>
+		/// Event handler for when the End/Leave Session menu entry is selected.
+		/// </summary>
+		void LeaveSessionMenuEntrySelected(object sender, PlayerIndexEventArgs e)
+		{
+			NetworkSessionComponent.LeaveSession(ScreenManager, e.PlayerIndex);
+		}
+
+
+	}
+}

+ 38 - 42
NetworkStateManagement/Screens/PlayerIndexEventArgs.cs → NetworkStateManagement/Core/Screens/PlayerIndexEventArgs.cs

@@ -1,42 +1,38 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// PlayerIndexEventArgs.cs
-//
-// XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using Microsoft.Xna.Framework;
-#endregion
-
-namespace NetworkStateManagement
-{
-    /// <summary>
-    /// Custom event argument which includes the index of the player who
-    /// triggered the event. This is used by the MenuEntry.Selected event.
-    /// </summary>
-    class PlayerIndexEventArgs : EventArgs
-    {
-        /// <summary>
-        /// Constructor.
-        /// </summary>
-        public PlayerIndexEventArgs(PlayerIndex playerIndex)
-        {
-            this.playerIndex = playerIndex;
-        }
-
-
-        /// <summary>
-        /// Gets the index of the player who triggered this event.
-        /// </summary>
-        public PlayerIndex PlayerIndex
-        {
-            get { return playerIndex; }
-        }
-
-        PlayerIndex playerIndex;
-    }
-}
+//-----------------------------------------------------------------------------
+// PlayerIndexEventArgs.cs
+//
+// XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using Microsoft.Xna.Framework;
+
+namespace NetworkStateManagement
+{
+    /// <summary>
+    /// Custom event argument which includes the index of the player who
+    /// triggered the event. This is used by the MenuEntry.Selected event.
+    /// </summary>
+    class PlayerIndexEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public PlayerIndexEventArgs(PlayerIndex playerIndex)
+        {
+            this.playerIndex = playerIndex;
+        }
+
+
+        /// <summary>
+        /// Gets the index of the player who triggered this event.
+        /// </summary>
+        public PlayerIndex PlayerIndex
+        {
+            get { return playerIndex; }
+        }
+
+        PlayerIndex playerIndex;
+    }
+}

+ 0 - 180
NetworkStateManagement/NetworkStateManagement.Linux.csproj

@@ -1,180 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>NetworkStateManagement</RootNamespace>
-    <AssemblyName>NetworkStateManagement</AssemblyName>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
-    <PlatformTarget>x86</PlatformTarget>
-    <DebugSymbols>True</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
-    <PlatformTarget>x86</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Game.cs">
-      <Link>Game.cs</Link>
-    </Compile>
-    <Compile Include="IMessageDisplay.cs">
-      <Link>IMessageDisplay.cs</Link>
-    </Compile>
-    <Compile Include="MessageDisplayComponent.cs">
-      <Link>MessageDisplayComponent.cs</Link>
-    </Compile>
-    <Compile Include="Networking\AvailableSessionMenuEntry.cs">
-      <Link>Networking\AvailableSessionMenuEntry.cs</Link>
-    </Compile>
-    <Compile Include="Networking\CreateOrFindSessionScreen.cs">
-      <Link>Networking\CreateOrFindSessionScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\JoinSessionScreen.cs">
-      <Link>Networking\JoinSessionScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\LobbyScreen.cs">
-      <Link>Networking\LobbyScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\NetworkBusyScreen.cs">
-      <Link>Networking\NetworkBusyScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\NetworkErrorScreen.cs">
-      <Link>Networking\NetworkErrorScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\NetworkSessionComponent.cs">
-      <Link>Networking\NetworkSessionComponent.cs</Link>
-    </Compile>
-    <Compile Include="Networking\OperationCompletedEventArgs.cs">
-      <Link>Networking\OperationCompletedEventArgs.cs</Link>
-    </Compile>
-    <Compile Include="Networking\ProfileSignInScreen.cs">
-      <Link>Networking\ProfileSignInScreen.cs</Link>
-    </Compile>
-    <Compile Include="ScreenManager\GameScreen.cs">
-      <Link>ScreenManager\GameScreen.cs</Link>
-    </Compile>
-    <Compile Include="ScreenManager\InputState.cs">
-      <Link>ScreenManager\InputState.cs</Link>
-    </Compile>
-    <Compile Include="ScreenManager\ScreenManager.cs">
-      <Link>ScreenManager\ScreenManager.cs</Link>
-    </Compile>
-    <Compile Include="Screens\BackgroundScreen.cs">
-      <Link>Screens\BackgroundScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\GameplayScreen.cs">
-      <Link>Screens\GameplayScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\LoadingScreen.cs">
-      <Link>Screens\LoadingScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MainMenuScreen.cs">
-      <Link>Screens\MainMenuScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MenuEntry.cs">
-      <Link>Screens\MenuEntry.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MenuScreen.cs">
-      <Link>Screens\MenuScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MessageBoxScreen.cs">
-      <Link>Screens\MessageBoxScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\PauseMenuScreen.cs">
-      <Link>Screens\PauseMenuScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\PlayerIndexEventArgs.cs">
-      <Link>Screens\PlayerIndexEventArgs.cs</Link>
-    </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Resources.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DesignTime>True</DesignTime>
-      <DependentUpon>Resources.resx</DependentUpon>
-    </Compile>
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\background.xnb">
-      <Link>Content\background.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\blank.xnb">
-      <Link>Content\blank.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\cat.xnb">
-      <Link>Content\cat.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_able.xnb">
-      <Link>Content\chat_able.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_mute.xnb">
-      <Link>Content\chat_mute.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_ready.xnb">
-      <Link>Content\chat_ready.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_talking.xnb">
-      <Link>Content\chat_talking.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\gamefont.xnb">
-      <Link>Content\gamefont.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\gradient.xnb">
-      <Link>Content\gradient.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
-      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
-    </EmbeddedResource>
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\menufont.xnb">
-      <Link>Content\menufont.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>

+ 0 - 124
NetworkStateManagement/NetworkStateManagement.MacOS.csproj

@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{71871CF8-8563-4FA3-ABF2-EC1CBBF817E4}</ProjectGuid>
-    <ProjectTypeGuids>{948B3504-5B70-4649-8FE4-BDE1FB46EC69};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>NetworkStateManagement</RootNamespace>
-    <AssemblyName>NetworkStateManagement</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>True</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;MONOMAC</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>False</ConsolePause>
-    <EnableCodeSigning>False</EnableCodeSigning>
-    <CreatePackage>False</CreatePackage>
-    <EnablePackageSigning>False</EnablePackageSigning>
-    <IncludeMonoRuntime>False</IncludeMonoRuntime>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>none</DebugType>
-    <Optimize>False</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>False</ConsolePause>
-    <EnableCodeSigning>False</EnableCodeSigning>
-    <CreatePackage>False</CreatePackage>
-    <EnablePackageSigning>False</EnablePackageSigning>
-    <IncludeMonoRuntime>False</IncludeMonoRuntime>
-    <DefineConstants>MONOMAC</DefineConstants>
-    <UseSGen>False</UseSGen>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="MonoMac" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Info.plist">
-    </None>
-    <None Include="Content\background.png" />
-    <None Include="Content\blank.png" />
-    <None Include="Content\cat.tga" />
-    <None Include="Content\chat_able.png" />
-    <None Include="Content\chat_mute.png" />
-    <None Include="Content\chat_ready.png" />
-    <None Include="Content\chat_talking.png" />
-    <None Include="Content\gamefont.spritefont" />
-    <None Include="Content\gradient.png" />
-    <None Include="Content\menufont.spritefont" />
-    <None Include="Game.ico" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
-  <ItemGroup>
-    <Folder Include="Content\" />
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\background.xnb" />
-    <Content Include="Content\blank.xnb" />
-    <Content Include="Content\cat.xnb" />
-    <Content Include="Content\chat_able.xnb" />
-    <Content Include="Content\chat_mute.xnb" />
-    <Content Include="Content\chat_ready.xnb" />
-    <Content Include="Content\chat_talking.xnb" />
-    <Content Include="Content\gamefont.xnb" />
-    <Content Include="Content\gradient.xnb" />
-    <Content Include="Content\menufont.xnb" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Networking\AvailableSessionMenuEntry.cs" />
-    <Compile Include="Networking\CreateOrFindSessionScreen.cs" />
-    <Compile Include="Networking\JoinSessionScreen.cs" />
-    <Compile Include="Networking\LobbyScreen.cs" />
-    <Compile Include="Networking\NetworkBusyScreen.cs" />
-    <Compile Include="Networking\NetworkErrorScreen.cs" />
-    <Compile Include="Networking\NetworkSessionComponent.cs" />
-    <Compile Include="Networking\OperationCompletedEventArgs.cs" />
-    <Compile Include="Networking\ProfileSignInScreen.cs" />
-    <Compile Include="ScreenManager\GameScreen.cs" />
-    <Compile Include="ScreenManager\InputState.cs" />
-    <Compile Include="ScreenManager\ScreenManager.cs" />
-    <Compile Include="Screens\BackgroundScreen.cs" />
-    <Compile Include="Screens\GameplayScreen.cs" />
-    <Compile Include="Screens\LoadingScreen.cs" />
-    <Compile Include="Screens\MainMenuScreen.cs" />
-    <Compile Include="Screens\MenuEntry.cs" />
-    <Compile Include="Screens\MenuScreen.cs" />
-    <Compile Include="Screens\MessageBoxScreen.cs" />
-    <Compile Include="Screens\PauseMenuScreen.cs" />
-    <Compile Include="Screens\PlayerIndexEventArgs.cs" />
-    <Compile Include="Game.cs" />
-    <Compile Include="IMessageDisplay.cs" />
-    <Compile Include="MessageDisplayComponent.cs" />
-    <Compile Include="Resources.Designer.cs" />
-    <Compile Include="Program.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources.resx" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\ThirdParty\Lidgren.Network\Lidgren.Network.MacOS.csproj">
-      <Project>{AE483C29-042E-4226-BA52-D247CE7676DA}</Project>
-      <Name>Lidgren.Network.MacOS</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.MacOS.csproj">
-      <Project>{36C538E6-C32A-4A8D-A39C-566173D7118E}</Project>
-      <Name>MonoGame.Framework.MacOS</Name>
-    </ProjectReference>
-  </ItemGroup>
-</Project>

+ 0 - 188
NetworkStateManagement/NetworkStateManagement.Windows.csproj

@@ -1,188 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProductVersion>8.0.30703</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>NetworkStateManagement</RootNamespace>
-    <AssemblyName>NetworkStateManagement</AssemblyName>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
-    <PlatformTarget>x86</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
-    <PlatformTarget>x86</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Game.cs">
-      <Link>Game.cs</Link>
-    </Compile>
-    <Compile Include="IMessageDisplay.cs">
-      <Link>IMessageDisplay.cs</Link>
-    </Compile>
-    <Compile Include="MessageDisplayComponent.cs">
-      <Link>MessageDisplayComponent.cs</Link>
-    </Compile>
-    <Compile Include="Networking\AvailableSessionMenuEntry.cs">
-      <Link>Networking\AvailableSessionMenuEntry.cs</Link>
-    </Compile>
-    <Compile Include="Networking\CreateOrFindSessionScreen.cs">
-      <Link>Networking\CreateOrFindSessionScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\JoinSessionScreen.cs">
-      <Link>Networking\JoinSessionScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\LobbyScreen.cs">
-      <Link>Networking\LobbyScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\NetworkBusyScreen.cs">
-      <Link>Networking\NetworkBusyScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\NetworkErrorScreen.cs">
-      <Link>Networking\NetworkErrorScreen.cs</Link>
-    </Compile>
-    <Compile Include="Networking\NetworkSessionComponent.cs">
-      <Link>Networking\NetworkSessionComponent.cs</Link>
-    </Compile>
-    <Compile Include="Networking\OperationCompletedEventArgs.cs">
-      <Link>Networking\OperationCompletedEventArgs.cs</Link>
-    </Compile>
-    <Compile Include="Networking\ProfileSignInScreen.cs">
-      <Link>Networking\ProfileSignInScreen.cs</Link>
-    </Compile>
-    <Compile Include="ScreenManager\GameScreen.cs">
-      <Link>ScreenManager\GameScreen.cs</Link>
-    </Compile>
-    <Compile Include="ScreenManager\InputState.cs">
-      <Link>ScreenManager\InputState.cs</Link>
-    </Compile>
-    <Compile Include="ScreenManager\ScreenManager.cs">
-      <Link>ScreenManager\ScreenManager.cs</Link>
-    </Compile>
-    <Compile Include="Screens\BackgroundScreen.cs">
-      <Link>Screens\BackgroundScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\GameplayScreen.cs">
-      <Link>Screens\GameplayScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\LoadingScreen.cs">
-      <Link>Screens\LoadingScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MainMenuScreen.cs">
-      <Link>Screens\MainMenuScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MenuEntry.cs">
-      <Link>Screens\MenuEntry.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MenuScreen.cs">
-      <Link>Screens\MenuScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\MessageBoxScreen.cs">
-      <Link>Screens\MessageBoxScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\PauseMenuScreen.cs">
-      <Link>Screens\PauseMenuScreen.cs</Link>
-    </Compile>
-    <Compile Include="Screens\PlayerIndexEventArgs.cs">
-      <Link>Screens\PlayerIndexEventArgs.cs</Link>
-    </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Resources.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DesignTime>True</DesignTime>
-      <DependentUpon>Resources.resx</DependentUpon>
-    </Compile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\MonoGame.Framework\MonoGame.Framework.Windows.csproj">
-      <Project>{7DE47032-A904-4C29-BD22-2D235E8D91BA}</Project>
-      <Name>MonoGame.Framework.Windows</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\background.xnb">
-      <Link>Content\background.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\blank.xnb">
-      <Link>Content\blank.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\cat.xnb">
-      <Link>Content\cat.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_able.xnb">
-      <Link>Content\chat_able.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_mute.xnb">
-      <Link>Content\chat_mute.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_ready.xnb">
-      <Link>Content\chat_ready.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\chat_talking.xnb">
-      <Link>Content\chat_talking.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\gamefont.xnb">
-      <Link>Content\gamefont.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-    <Content Include="Content\gradient.xnb">
-      <Link>Content\gradient.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-  </ItemGroup>
-  <ItemGroup>
-    <EmbeddedResource Include="Resources.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
-      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
-    </EmbeddedResource>
-  </ItemGroup>
-  <ItemGroup>
-    <Content Include="Content\menufont.xnb">
-      <Link>Content\menufont.xnb</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>

+ 42 - 24
NetworkStateManagement/NetworkStateManagement.sln

@@ -1,37 +1,55 @@
 
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkStateManagement", "NetworkStateManagement.csproj", "{71871CF8-8563-4FA3-ABF2-EC1CBBF817E4}"
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36301.6 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkStateManagement.Core", "Core\NetworkStateManagement.Core.csproj", "{A1B2C3D4-1234-5678-ABCD-1234567890AB}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Framework.MacOS", "..\..\..\..\..\..\..\Users\Jimmy\Public\Share\MonoMacSource\kjpgit\MonoGame\MonoGame.Framework\MonoGame.Framework.MacOS.csproj", "{36C538E6-C32A-4A8D-A39C-566173D7118E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkStateManagement.Windows", "Platforms\Windows\NetworkStateManagement.Windows.csproj", "{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network", "..\..\..\lidgren-network-gen3\Lidgren.Network\Lidgren.Network.csproj", "{AE483C29-042E-4226-BA52-D247CE7676DA}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkStateManagement.DesktopGL", "Platforms\Desktop\NetworkStateManagement.DesktopGL.csproj", "{E1A1C2D3-45F6-7890-ABCD-EF1234567890}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkStateManagement.Android", "Platforms\Android\NetworkStateManagement.Android.csproj", "{F2B3C4D5-67E8-9012-3456-7890ABCDEF12}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkStateManagement.iOS", "Platforms\iOS\NetworkStateManagement.iOS.csproj", "{B1C2D3E4-2345-6789-BCDE-2345678901BC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Xna.Framework.Net", "..\MonoGame.Xna.Framework.Net\MonoGame.Xna.Framework.Net.csproj", "{86E1E7AD-DD62-384D-A073-092A5F875CF0}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
-		Distribution|Any CPU = Distribution|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Distribution|Any CPU.ActiveCfg = Distribution|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Distribution|Any CPU.Build.0 = Distribution|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{36C538E6-C32A-4A8D-A39C-566173D7118E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{71871CF8-8563-4FA3-ABF2-EC1CBBF817E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{71871CF8-8563-4FA3-ABF2-EC1CBBF817E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{71871CF8-8563-4FA3-ABF2-EC1CBBF817E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{71871CF8-8563-4FA3-ABF2-EC1CBBF817E4}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AE483C29-042E-4226-BA52-D247CE7676DA}.Distribution|Any CPU.ActiveCfg = Debug|Any CPU
-		{AE483C29-042E-4226-BA52-D247CE7676DA}.Distribution|Any CPU.Build.0 = Debug|Any CPU
-		{AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A1B2C3D4-1234-5678-ABCD-1234567890AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A1B2C3D4-1234-5678-ABCD-1234567890AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A1B2C3D4-1234-5678-ABCD-1234567890AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A1B2C3D4-1234-5678-ABCD-1234567890AB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E1A1C2D3-45F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E1A1C2D3-45F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E1A1C2D3-45F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E1A1C2D3-45F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F2B3C4D5-67E8-9012-3456-7890ABCDEF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F2B3C4D5-67E8-9012-3456-7890ABCDEF12}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F2B3C4D5-67E8-9012-3456-7890ABCDEF12}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F2B3C4D5-67E8-9012-3456-7890ABCDEF12}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B1C2D3E4-2345-6789-BCDE-2345678901BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B1C2D3E4-2345-6789-BCDE-2345678901BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B1C2D3E4-2345-6789-BCDE-2345678901BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B1C2D3E4-2345-6789-BCDE-2345678901BC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{86E1E7AD-DD62-384D-A073-092A5F875CF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{86E1E7AD-DD62-384D-A073-092A5F875CF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{86E1E7AD-DD62-384D-A073-092A5F875CF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{86E1E7AD-DD62-384D-A073-092A5F875CF0}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
 	EndGlobalSection
-	GlobalSection(MonoDevelopProperties) = preSolution
-		StartupItem = NetworkStateManagement.csproj
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {771DE562-A8C4-4266-9773-DEEC69DCB3DE}
 	EndGlobalSection
 EndGlobal

+ 0 - 210
NetworkStateManagement/Networking/CreateOrFindSessionScreen.cs

@@ -1,210 +0,0 @@
-#region File Description
-//-----------------------------------------------------------------------------
-// CreateOrFindSessionScreen.cs
-//
-// Microsoft XNA Community Game Platform
-// Copyright (C) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
-#endregion
-
-#region Using Statements
-using System;
-using System.Collections.Generic;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Net;
-using Microsoft.Xna.Framework.GamerServices;
-
-#endregion
-
-namespace NetworkStateManagement
-{
-	/// <summary>
-	/// This menu screen lets the user choose whether to create a new
-	/// network session, or search for an existing session to join.
-	/// </summary>
-	class CreateOrFindSessionScreen : MenuScreen
-	{
-	#region Fields
-
-		NetworkSessionType sessionType;
-
-	#endregion
-
-	#region Initialization
-
-
-		/// <summary>
-		/// Constructor fills in the menu contents.
-		/// </summary>
-		public CreateOrFindSessionScreen (NetworkSessionType sessionType)
-		: base(GetMenuTitle(sessionType))
-			{
-			this.sessionType = sessionType;
-
-			// Create our menu entries.
-			MenuEntry createSessionMenuEntry = new MenuEntry (Resources.CreateSession);
-			MenuEntry findSessionsMenuEntry = new MenuEntry (Resources.FindSessions);
-			MenuEntry backMenuEntry = new MenuEntry (Resources.Back);
-
-			// Hook up menu event handlers.
-			createSessionMenuEntry.Selected += CreateSessionMenuEntrySelected;
-			findSessionsMenuEntry.Selected += FindSessionsMenuEntrySelected;
-			backMenuEntry.Selected += OnCancel;
-
-			// Add entries to the menu.
-			MenuEntries.Add (createSessionMenuEntry);
-			MenuEntries.Add (findSessionsMenuEntry);
-			MenuEntries.Add (backMenuEntry);
-		}
-
-
-		/// <summary>
-		/// Helper chooses an appropriate menu title for the specified session type.
-		/// </summary>
-		static string GetMenuTitle (NetworkSessionType sessionType)
-		{
-			switch (sessionType) {
-			case NetworkSessionType.PlayerMatch:
-				return Resources.PlayerMatch;
-
-			case NetworkSessionType.SystemLink:
-				return Resources.SystemLink;
-
-			default:
-				throw new NotSupportedException ();
-			}
-		}
-
-
-	#endregion
-
-	#region Event Handlers
-
-
-		/// <summary>
-		/// Event handler for when the Create Session menu entry is selected.
-		/// </summary>
-		void CreateSessionMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			try			{
-				// Which local profiles should we include in this session?
-				IEnumerable<SignedInGamer> localGamers = 
-			NetworkSessionComponent.ChooseGamers (sessionType, 
-							ControllingPlayer.Value);
-
-				// Begin an asynchronous create network session operation.
-				IAsyncResult asyncResult = NetworkSession.BeginCreate (
-						sessionType, localGamers, 
-						NetworkSessionComponent.MaxGamers, 
-						0, null, null, null);
-
-				// Activate the network busy screen, which will display
-				// an animation until this operation has completed.
-				NetworkBusyScreen busyScreen = new NetworkBusyScreen (asyncResult);
-
-				busyScreen.OperationCompleted += CreateSessionOperationCompleted;
-
-				ScreenManager.AddScreen (busyScreen, ControllingPlayer);
-			} catch (Exception exception) {
-				NetworkErrorScreen errorScreen = new NetworkErrorScreen (exception);
-
-				ScreenManager.AddScreen (errorScreen, ControllingPlayer);
-			}
-		}
-
-		enum SessionProperty{ GameMode, SkillLevel, ScoreToWin }
-		
-		enum GameMode{ Practice, Timed, CaptureTheFlag }
-		
-		enum SkillLevel{ Beginner, Intermediate, Advanced }
-		
-		/// <summary>
-		/// Event handler for when the asynchronous create network session
-		/// operation has completed.
-		/// </summary>
-		void CreateSessionOperationCompleted (object sender,
-					OperationCompletedEventArgs e)
-		{
-			try			{
-				// End the asynchronous create network session operation.
-				NetworkSession networkSession = NetworkSession.EndCreate (e.AsyncResult);
-				
-				// Create a component that will manage the session we just created.
-				NetworkSessionComponent.Create (ScreenManager, networkSession);
-
-				// Go to the lobby screen. We pass null as the controlling player,
-				// because the lobby screen accepts input from all local players
-				// who are in the session, not just a single controlling player.
-				ScreenManager.AddScreen (new LobbyScreen (networkSession), null);
-			} catch (Exception exception) {
-				NetworkErrorScreen errorScreen = new NetworkErrorScreen (exception);
-
-				ScreenManager.AddScreen (errorScreen, ControllingPlayer);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the Find Sessions menu entry is selected.
-		/// </summary>
-		void FindSessionsMenuEntrySelected (object sender, PlayerIndexEventArgs e)
-		{
-			try			{
-				// Which local profiles should we include in this session?
-				IEnumerable<SignedInGamer> localGamers = 
-			NetworkSessionComponent.ChooseGamers (sessionType, 
-							ControllingPlayer.Value);
-
-				// Begin an asynchronous find network sessions operation.
-				IAsyncResult asyncResult = NetworkSession.BeginFind (sessionType, 
-							localGamers, null, null, null);
-
-				// Activate the network busy screen, which will display
-				// an animation until this operation has completed.
-				NetworkBusyScreen busyScreen = new NetworkBusyScreen (asyncResult);
-
-				busyScreen.OperationCompleted += FindSessionsOperationCompleted;
-
-				ScreenManager.AddScreen (busyScreen, ControllingPlayer);
-			} catch (Exception exception) {
-				NetworkErrorScreen errorScreen = new NetworkErrorScreen (exception);
-
-				ScreenManager.AddScreen (errorScreen, ControllingPlayer);
-			}
-		}
-
-
-		/// <summary>
-		/// Event handler for when the asynchronous find network sessions
-		/// operation has completed.
-		/// </summary>
-		void FindSessionsOperationCompleted (object sender,
-					OperationCompletedEventArgs e)
-		{
-			GameScreen nextScreen;
-
-			try			{
-				// End the asynchronous find network sessions operation.
-				AvailableNetworkSessionCollection availableSessions = 
-						NetworkSession.EndFind (e.AsyncResult);
-
-				if (availableSessions.Count == 0) {
-					// If we didn't find any sessions, display an error.
-					availableSessions.Dispose ();
-
-					nextScreen = new MessageBoxScreen (Resources.NoSessionsFound, false);
-				} else {
-					// If we did find some sessions, proceed to the JoinSessionScreen.
-					nextScreen = new JoinSessionScreen (availableSessions);
-				}
-			} catch (Exception exception) {
-				nextScreen = new NetworkErrorScreen (exception);
-			}
-
-			ScreenManager.AddScreen (nextScreen, ControllingPlayer);
-		}
-
-
-	#endregion
-	}
-}

+ 14 - 0
NetworkStateManagement/Platforms/Android/AndroidManifest.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.NetworkStateManagement">
+  <application android:label="NetworkStateManagement">
+    <activity android:name="android.app.NativeActivity"
+              android:label="NetworkStateManagement"
+              android:configChanges="orientation|keyboardHidden">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+  </application>
+  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
+</manifest>

+ 19 - 0
NetworkStateManagement/Platforms/Android/MainActivity.cs

@@ -0,0 +1,19 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using Microsoft.Xna.Framework;
+
+namespace NetworkStateManagement
+{
+    [Activity(Label = "NetworkStateManagement", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
+    public class MainActivity : AndroidGameActivity
+    {
+        protected override void OnCreate(Bundle savedInstanceState)
+        {
+            base.OnCreate(savedInstanceState);
+            var game = new NetworkStateManagementGame();
+            SetContentView((game.Services.GetService(typeof(View)) as View));
+            game.Run();
+        }
+    }
+}

+ 29 - 0
NetworkStateManagement/Platforms/Android/NetworkStateManagement.Android.csproj

@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-android</TargetFramework>
+    <RootNamespace>NetworkStateManagement</RootNamespace>
+    <AssemblyName>NetworkStateManagement.Android</AssemblyName>
+    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
+    <AssemblyTitle>NetworkStateManagement</AssemblyTitle>
+    <AssemblyDescription></AssemblyDescription>
+    <AssemblyConfiguration></AssemblyConfiguration>
+    <Company>Microsoft</Company>
+    <Product>NetworkStateManagement</Product>
+    <Copyright>Copyright © Microsoft 2011</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+    <FileVersion>1.0.0.0</FileVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.Android" Version="3.8.*" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\NetworkStateManagement.Core.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+</Project>

+ 0 - 0
NetworkStateManagement/Platforms/Android/Program.cs


+ 29 - 0
NetworkStateManagement/Platforms/Desktop/NetworkStateManagement.DesktopGL.csproj

@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <RootNamespace>NetworkStateManagement</RootNamespace>
+    <AssemblyName>NetworkStateManagement.DesktopGL</AssemblyName>
+    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
+    <AssemblyTitle>NetworkStateManagement</AssemblyTitle>
+    <AssemblyDescription></AssemblyDescription>
+    <AssemblyConfiguration></AssemblyConfiguration>
+    <Company>Microsoft</Company>
+    <Product>NetworkStateManagement</Product>
+    <Copyright>Copyright © Microsoft 2011</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+    <FileVersion>1.0.0.0</FileVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\NetworkStateManagement.Core.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+</Project>

+ 15 - 0
NetworkStateManagement/Platforms/Desktop/Program.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace NetworkStateManagement.DesktopGL
+{
+    public static class Program
+    {
+        static void Main(string[] args)
+        {
+            using (var game = new NetworkStateManagementGame())
+            {
+                game.Run();
+            }
+        }
+    }
+}

+ 30 - 0
NetworkStateManagement/Platforms/Windows/NetworkStateManagement.Windows.csproj

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-windows</TargetFramework>
+    <RootNamespace>NetworkStateManagement</RootNamespace>
+    <AssemblyName>NetworkStateManagement</AssemblyName>
+    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
+    <AssemblyTitle>NetworkStateManagement</AssemblyTitle>
+    <AssemblyDescription></AssemblyDescription>
+    <AssemblyConfiguration></AssemblyConfiguration>
+    <Company>Microsoft</Company>
+    <Product>NetworkStateManagement</Product>
+    <Copyright>Copyright © Microsoft 2011</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+    <FileVersion>1.0.0.0</FileVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.WindowsDX" Version="3.8.*" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\NetworkStateManagement.Core.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+</Project>

+ 16 - 0
NetworkStateManagement/Platforms/Windows/Program.cs

@@ -0,0 +1,16 @@
+using System;
+
+namespace NetworkStateManagement.Windows
+{
+    public static class Program
+    {
+        [STAThread]
+        static void Main()
+        {
+            using (var game = new NetworkStateManagementGame())
+            {
+                game.Run();
+            }
+        }
+    }
+}

+ 19 - 0
NetworkStateManagement/Platforms/iOS/AppDelegate.cs

@@ -0,0 +1,19 @@
+using Foundation;
+using UIKit;
+using Microsoft.Xna.Framework;
+
+namespace NetworkStateManagement.iOS
+{
+    [Register("AppDelegate")]
+    public class AppDelegate : UIApplicationDelegate
+    {
+        private Game game;
+
+        public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
+        {
+            game = new NetworkStateManagementGame();
+            game.Run();
+            return true;
+        }
+    }
+}

+ 7 - 7
NetworkStateManagement/Info.plist → NetworkStateManagement/Platforms/iOS/Info.plist

@@ -2,15 +2,15 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>CFBundleIdentifier</key>
-	<string>com.yourcompany.NetworkStateManagement</string>
 	<key>CFBundleName</key>
 	<string>NetworkStateManagement</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.example.NetworkStateManagement</string>
 	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSMinimumSystemVersion</key>
-	<string>10.6</string>
-	<key>NSPrincipalClass</key>
-	<string>NSApplication</string>
+	<string>1.0</string>
+	<key>CFBundleExecutable</key>
+	<string>NetworkStateManagement</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
 </dict>
 </plist>

+ 29 - 0
NetworkStateManagement/Platforms/iOS/NetworkStateManagement.iOS.csproj

@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0-ios</TargetFramework>
+    <RootNamespace>NetworkStateManagement</RootNamespace>
+    <AssemblyName>NetworkStateManagement.iOS</AssemblyName>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <AssemblyTitle>NetworkStateManagement</AssemblyTitle>
+    <AssemblyDescription></AssemblyDescription>
+    <AssemblyConfiguration></AssemblyConfiguration>
+    <Company>Microsoft</Company>
+    <Product>NetworkStateManagement</Product>
+    <Copyright>Copyright © Microsoft 2011</Copyright>
+    <Trademark></Trademark>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+    <FileVersion>1.0.0.0</FileVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.iOS" Version="3.8.*" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Core\NetworkStateManagement.Core.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\Core\Content\**\*.xnb" Link="Content\%(RecursiveDir)%(Filename)%(Extension)">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+</Project>

+ 13 - 0
NetworkStateManagement/Platforms/iOS/Program.cs

@@ -0,0 +1,13 @@
+using UIKit;
+
+namespace NetworkStateManagement.iOS
+{
+    public class Application
+    {
+        // This is the main entry point of the application.
+        static void Main(string[] args)
+        {
+            UIApplication.Main(args, null, typeof(AppDelegate));
+        }
+    }
+}

+ 0 - 64
NetworkStateManagement/Program.cs

@@ -1,64 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-#if MONOMAC
-using MonoMac.AppKit;
-using MonoMac.Foundation;
-#endif
-
-namespace NetworkStateManagement
-{
-	#region Entry Point
-#if MONOMAC
-	static class Program
-	{
-		/// <summary>
-		/// The main entry point for the application.
-		/// </summary>
-		static void Main (string[] args)
-		{
-			NSApplication.Init ();
-			
-			using (var p = new NSAutoreleasePool ()) {
-				NSApplication.SharedApplication.Delegate = new AppDelegate();
-				NSApplication.Main(args);
-			}
-
-
-		}
-	}
-	
-	class AppDelegate : NSApplicationDelegate
-	{
-		
-		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
-		{
-			NetworkStateManagementGame game = new NetworkStateManagementGame ();
-			game.Run ();
-		}
-		
-		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
-		{
-			return true;
-		}
-	}	
-#else
-    static class Program
-    {
-        private static NetworkStateManagementGame game;
-
-        /// <summary>
-        /// The main entry point for the application.
-        /// </summary>
-        [STAThread]
-        static void Main()
-        {
-            game = new NetworkStateManagementGame();
-            game.Run();
-        }
-    }
-#endif
-	#endregion
-}
-

+ 0 - 36
NetworkStateManagement/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("NetworkStateManagement")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Microsoft")]
-[assembly: AssemblyProduct("NetworkStateManagement")]
-[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("c5101010-89f6-4096-bd46-893825393de4")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 48 - 0
NetworkStateManagement/README.md

@@ -0,0 +1,48 @@
+
+# NetworkStateManagement
+
+NetworkStateManagement is a MonoGame-based project demonstrating network state management in a game. It supports the following platforms:
+- Windows
+- DesktopGL
+- Android
+- iOS
+
+## Directory Structure
+
+- `/Core` - Shared game logic and code
+- `/Platforms/Windows` - Windows-specific entry point and project
+- `/Platforms/Desktop` - DesktopGL-specific entry point and project
+- `/Platforms/Android` - Android-specific entry point and project
+- `/Platforms/iOS` - iOS-specific entry point and project
+
+## Prerequisites
+- .NET 8.0 SDK or later
+- MonoGame 3.8.*
+- Visual Studio Code or Visual Studio
+
+## Building and Running
+
+### Windows
+1. Open the project folder in Visual Studio Code.
+2. Use the `build-windows` task to build the project.
+3. Use the `Launch Windows` configuration in the debugger to run the project.
+
+### DesktopGL
+1. Open the project folder in Visual Studio Code.
+2. Use the `build-desktopgl` task to build the project.
+3. Use the `Launch DesktopGL` configuration in the debugger to run the project.
+
+### Android
+1. Open the project folder in Visual Studio Code or Visual Studio.
+2. Use the `build-android` task to build the project.
+3. Use the `Launch Android` configuration in the debugger to run the project.
+
+### iOS
+1. Open the project folder in Visual Studio Code or Visual Studio.
+2. Use the `build-ios` task to build the project.
+3. Use the `Launch iOS` configuration in the debugger to run the project.
+
+## Notes
+- The project uses precompiled `.xnb` files for content, located in the `Content` folder.
+- All platform-specific code is separated into its own directory to avoid `#if/#endif` blocks.
+- Shared code is referenced from `/Core`.

+ 0 - 0
NetworkStateManagement/launch.json


+ 0 - 0
NetworkStateManagement/tasks.json