]> Dogcows Code - chaz/carfire/commitdiff
Implemented the base architecture we are bound to because of how the network code...
authorCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Sat, 10 Apr 2010 07:39:18 +0000 (07:39 +0000)
committerCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Sat, 10 Apr 2010 07:39:18 +0000 (07:39 +0000)
It's kind of like a walking skeleton... or a limping skeleton.

git-svn-id: https://bd85.net/svn/cs3505_group@57 92bb83a3-7c8f-8a45-bc97-515c4e399668

CarFire/CarFire/CarFire.suo
CarFire/CarFire/CarFire/CarFire.csproj
CarFire/CarFire/CarFire/ChatInfo.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/Game.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/IDeterministicGame.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/IScreenManager.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/NetworkManager.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/Program.cs
CarFire/CarFire/CarFire/ScreenManager.cs [new file with mode: 0644]
CarFire/CarFire/CarFire/XnaGame.cs [moved from CarFire/CarFire/CarFire/Game1.cs with 65% similarity]

index 8ebdb70438dcc4f4be891a99c91ecdf972b1070d..dd09ba19fe9e56eed8d46944c6f342d3069547ce 100644 (file)
Binary files a/CarFire/CarFire/CarFire.suo and b/CarFire/CarFire/CarFire.suo differ
index 994f3b31c2bc29b2b9bba07c3b4e589963c1559a..9d05f39c49e6ae9141f77a0a0dbe390834e15fca 100644 (file)
@@ -70,6 +70,7 @@
     <Reference Include="System">\r
       <Private>False</Private>\r
     </Reference>\r
+    <Reference Include="System.Data" />\r
     <Reference Include="System.Xml">\r
       <Private>False</Private>\r
     </Reference>\r
     </Reference>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Compile Include="ChatInfo.cs" />\r
+    <Compile Include="Game.cs" />\r
+    <Compile Include="IDeterministicGame.cs" />\r
+    <Compile Include="IScreenManager.cs" />\r
+    <Compile Include="NetworkManager.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
     <Compile Include="Program.cs" />\r
-    <Compile Include="Game1.cs" />\r
+    <Compile Include="XnaGame.cs" />\r
+    <Compile Include="ScreenManager.cs" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <Content Include="Game.ico" />\r
diff --git a/CarFire/CarFire/CarFire/ChatInfo.cs b/CarFire/CarFire/CarFire/ChatInfo.cs
new file mode 100644 (file)
index 0000000..fa6c0d1
--- /dev/null
@@ -0,0 +1,52 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework.Net;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// Small container class for the information concerning a chat packet.\r
+    /// It is immutable.\r
+    /// </summary>\r
+    public class ChatInfo\r
+    {\r
+        // Private member variables\r
+        #region Instance Variables\r
+\r
+        NetworkGamer mSender;\r
+        String mMessage;\r
+\r
+        #endregion\r
+\r
+\r
+        /// <summary>\r
+        /// Get the sender who sent the chat packet.\r
+        /// </summary>\r
+        public NetworkGamer Sender\r
+        {\r
+            get { return mSender; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get the message that was sent by the sender.\r
+        /// </summary>\r
+        public String Message\r
+        {\r
+            get { return mMessage; }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Construct a chat packet with contents.\r
+        /// </summary>\r
+        /// <param name="sender">The chat sender.</param>\r
+        /// <param name="message">The chat message.</param>\r
+        public ChatInfo(NetworkGamer sender, String message)\r
+        {\r
+            mSender = sender;\r
+            mMessage = message;\r
+        }\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/Game.cs b/CarFire/CarFire/CarFire/Game.cs
new file mode 100644 (file)
index 0000000..1650634
--- /dev/null
@@ -0,0 +1,87 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+using Microsoft.Xna.Framework.Input;\r
+\r
+namespace CarFire\r
+{\r
+    class Game : IDeterministicGame\r
+    {\r
+        #region IDeterministicGame Members\r
+\r
+        public void LoadContent(ContentManager contentManager)\r
+        {\r
+        }\r
+\r
+        public void UnloadContent()\r
+        {\r
+        }\r
+\r
+        public Vector2 PreferredScreenSize\r
+        {\r
+            get { return new Vector2(800, 600); }\r
+        }\r
+\r
+        public int MinimumSupportedPlayers\r
+        {\r
+            get { return 1; }\r
+        }\r
+\r
+        public int MaximumSupportedPlayers\r
+        {\r
+            get { return 4; }\r
+        }\r
+\r
+        public void ResetGame(object[] playerIdentifiers, object thisPlayer)\r
+        {\r
+        }\r
+\r
+        public long CurrentFrameNumber\r
+        {\r
+            get { return 0; }\r
+        }\r
+\r
+        public long CurrentChecksum\r
+        {\r
+            get { return 0; }\r
+        }\r
+\r
+        public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)\r
+        {\r
+        }\r
+\r
+        public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)\r
+        {\r
+        }\r
+\r
+        public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)\r
+        {\r
+        }\r
+\r
+        public bool IsGameOver(object playerIdentifier)\r
+        {\r
+            return true;\r
+        }\r
+\r
+        public bool IsTerminated(object playerIdentifier)\r
+        {\r
+            return true;\r
+        }\r
+\r
+        public long Update(TimeSpan timespan)\r
+        {\r
+            return CurrentFrameNumber;\r
+        }\r
+\r
+        public long Draw(SpriteBatch spriteBatch)\r
+        {\r
+            return CurrentFrameNumber;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/IDeterministicGame.cs b/CarFire/CarFire/CarFire/IDeterministicGame.cs
new file mode 100644 (file)
index 0000000..857f57a
--- /dev/null
@@ -0,0 +1,157 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Graphics;\r
+using Microsoft.Xna.Framework.Input;\r
+using Microsoft.Xna.Framework.Content;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// A DeterministicGame object is a full XNA game, except that it does not\r
+    /// extend the Microsoft.Xna.Framework.Game class.  It supports content loading\r
+    /// and unloading, as well as modified Update and Draw functionality.\r
+    /// \r
+    /// DeterministicGame objects are intented to be incorporated inside of an \r
+    /// existing game.  By simply calling update and draw at the appropriate times,\r
+    /// and by supplying user inputs, the game will play just like any other game.\r
+    /// \r
+    /// It is intended that a DeterministicGame be a multiplayer game, and support for\r
+    /// this is listed in the interface below.  Each player is identified by a unique object\r
+    /// reference (of the caller's choice, not a struct).  The game supports the notion of a\r
+    /// current 'frame', or state.  The enclosing code supplies the user inputs for the\r
+    /// next frame by calling methods.  The enclosing code then should call the update\r
+    /// method to advance the game to the next frame.  Finally, the enclosing code\r
+    /// calls the draw method to render the game state.  Note that the game state can\r
+    /// be drawn multiple times without updating the game, thus allowing the game\r
+    /// to be paused or stalled.\r
+    /// </summary>\r
+    public interface IDeterministicGame\r
+    {\r
+        /// <summary>\r
+        /// Call this method to give the game a chance to load its content.\r
+        /// </summary>\r
+        /// <param name="contentManager">A valid content manager pointing to the root of the content tree</param>\r
+        void LoadContent (ContentManager contentManager);\r
+\r
+        /// <summary>\r
+        /// Call this method to give the game a chance to unload its content.\r
+        /// </summary>\r
+        void UnloadContent();\r
+\r
+        /// <summary>\r
+        /// Returns the preferred screen size for this game.\r
+        /// </summary>\r
+        /// <returns></returns>\r
+        Vector2 PreferredScreenSize { get; }\r
+\r
+        /// <summary>\r
+        /// Returns the minimum number of players this game can support.\r
+        /// </summary>\r
+        /// <returns>the minimum player count</returns>\r
+        int MinimumSupportedPlayers { get; }\r
+\r
+        /// <summary>\r
+        /// Returns the maximum number of players this game can support.\r
+        /// </summary>\r
+        /// <returns>the maximum player count</returns>\r
+        int MaximumSupportedPlayers { get; }\r
+\r
+        /// <summary>\r
+        /// Call this method to reset the game state, to set the current frame at 0, and\r
+        /// to supply identifiers for each player in the game.  Player identifiers should\r
+        /// be unique object references (not structs) that the caller will use later\r
+        /// to identify each player.  (It is important that these not be 'boxed' object\r
+        /// references or the reference will not be preserved.)\r
+        /// \r
+        /// Since, in theory, there will be four copies of the game running, a second\r
+        /// parameter identifies the player that is running this copy of the game.\r
+        /// </summary>\r
+        /// <param name="playerIdentifiers">An array of objects (references) that will identify each player</param>\r
+        /// <param name="playerIdentifiers">An object identifier for the player whose machine is displaying this game</param>\r
+        void ResetGame(Object[] playerIdentifiers, Object thisPlayer);\r
+\r
+        /// <summary>\r
+        /// Returns the current frame number.  This corresponds to the current state\r
+        /// of the game world.\r
+        /// </summary>\r
+        /// <returns>the current frame number</returns>\r
+        long CurrentFrameNumber { get; }\r
+\r
+        /// <summary>\r
+        /// Returns a checksum of all of the game world state.  This checksum can be used\r
+        /// to ensure that multiple players at some frame all share the same state.  It is\r
+        /// guaranteed that identical states will produce identical checksums.\r
+        /// </summary>\r
+        /// <returns>the current game state checksum</returns>\r
+        long CurrentChecksum { get; }\r
+\r
+        /// <summary>\r
+        /// Call this method to report changes in keypresses to the game.  You should call this method\r
+        /// to report any changes in keyboard state for a player.  The keyboard state will be\r
+        /// applied to the next game state (not the current state).\r
+        /// </summary>\r
+        /// <param name="playerIdentifier">An object (reference) that was registered for a player in the game</param>\r
+        /// <param name="key">A key identifier</param>\r
+        /// <param name="isKeyPressed">The key state - true means pressed, false means released</param>\r
+        void ApplyKeyInput (Object playerIdentifier, Keys key, bool isKeyPressed);\r
+\r
+        /// <summary>\r
+        /// Call this method to report changes in mouse locations to the game.  You should call this method\r
+        /// any time the mouse coordinates for a player changes.  The mouse information will\r
+        /// be applied to the next game state (not the current state).\r
+        /// </summary>\r
+        /// <param name="playerIdentifier">an object (reference) that was registered for a player in the game</param>\r
+        /// <param name="x">the mouse x location</param>\r
+        /// <param name="y">the mouse y location</param>\r
+        void ApplyMouseLocationInput (Object playerIdentifier, int x, int y);\r
+\r
+        /// <summary>\r
+        /// Call this method to report changes in mouse button state to the game.  Note that only one\r
+        /// mouse button is supported in game.  You should call this method to report any\r
+        /// changes in mouse button state for a player.  The mouse button state will be\r
+        /// applied to the next game state (not the current state).\r
+        /// </summary>\r
+        /// <param name="playerIdentifier">an object (reference) that was registered for a player in the game</param>\r
+        /// <param name="isButtonPressed">the mouse button state</param>\r
+        void ApplyMouseButtonInput (Object playerIdentifier, bool isButtonPressed);\r
+\r
+        /// <summary>\r
+        /// Returns true if the specified player's game is over.  They can be safely disconnected from the game\r
+        /// when this flag is true, their inputs do not affect game state.  (You can continue to report inputs,\r
+        /// to allow the player to view a game over screen, but no game state action is taken.)\r
+        /// </summary>\r
+        /// <param name="playerIdentifier">an object (reference) that was registered for a player in the game</param>\r
+        /// <returns>true if the game is over</returns>\r
+        bool IsGameOver(Object playerIdentifier);\r
+\r
+        /// <summary>\r
+        /// Returns true if the specified player's game is over, and the player has clicked on something indicating\r
+        /// they wish to leave the game over screen.  (This only becomes true if inputs are reported\r
+        /// even after the game is over.)\r
+        /// </summary>\r
+        /// <param name="playerIdentifier">an object (reference) that was registered for a player in the game</param>\r
+        /// <returns>true if the player has terminated the game</returns>\r
+        bool IsTerminated(Object playerIdentifier);\r
+\r
+        /// <summary>\r
+        /// Call this method to advance the game state.  Previously sent inputs are applied\r
+        /// to the game state and the frame number is advanced and returned.  Caution should be used when\r
+        /// supplying the seconds parameter - it can affect game state.  All players in a game\r
+        /// should advance their game time by the same amount.\r
+        /// </summary>\r
+        /// <param name="timespan">The elapsed game time</param>\r
+        /// <returns>the frame number of the new game state (now the current state)</returns>\r
+        long Update(TimeSpan timespan);\r
+\r
+        /// <summary>\r
+        /// Draws the current game state.  This does not affect the game state - it may be called\r
+        /// repeatedly to redraw the current game state if needed.\r
+        /// </summary>\r
+        /// <param name="spriteBatch">a SpriteBatch object that has begun a batch</param>\r
+        /// <returns>the current game state frame number</returns>\r
+        long Draw(SpriteBatch spriteBatch);\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/IScreenManager.cs b/CarFire/CarFire/CarFire/IScreenManager.cs
new file mode 100644 (file)
index 0000000..1b15e20
--- /dev/null
@@ -0,0 +1,19 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+using Microsoft.Xna.Framework.Input;\r
+\r
+namespace CarFire\r
+{\r
+    public interface IScreenManager\r
+    {\r
+        void LoadContent(ContentManager contentManager, GraphicsDeviceManager graphics);\r
+        void UnloadContent();\r
+        long Update(GameTime gameTime, NetworkManager networkGame);\r
+        long Draw(SpriteBatch spriteBatch);\r
+    }\r
+}\r
diff --git a/CarFire/CarFire/CarFire/NetworkManager.cs b/CarFire/CarFire/CarFire/NetworkManager.cs
new file mode 100644 (file)
index 0000000..3fd4ca4
--- /dev/null
@@ -0,0 +1,1065 @@
+\r
+// Make sure DEBUG is undefined when turning in the project\r
+// or the grader will wonder why it's so laggy.\r
+#undef DEBUG\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework.Net;\r
+using System.Diagnostics;\r
+using Microsoft.Xna.Framework.GamerServices;\r
+using Microsoft.Xna.Framework.Graphics;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Input;\r
+using System.Collections;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// A manager class to handle network interactions between peers and\r
+    /// lobby/game switching.\r
+    /// </summary>\r
+    public class NetworkManager\r
+    {\r
+        // Public methods and properties\r
+        #region Public Methods\r
+\r
+        /// <summary>\r
+        /// Called when a session has been created or joined using CreateSession() or JoinSession().\r
+        /// </summary>\r
+        /// <param name="session">The new session that was created or joined.</param>\r
+        /// <param name="networkGame">The NetworkGame that joined the session.</param>\r
+        public delegate void JoinedSessionDelegate(NetworkSession session, NetworkManager networkGame);\r
+\r
+        /// <summary>\r
+        /// Called when sessions are found as a result of calling FindSessions().\r
+        /// </summary>\r
+        /// <param name="sessions">A container of the available sessions.</param>\r
+        /// <param name="networkGame">The NetworkGame that searched for the sessions.</param>\r
+        public delegate void FoundSessionsDelegate(AvailableNetworkSessionCollection sessions, NetworkManager networkGame);\r
+\r
+\r
+        /// <summary>\r
+        /// Called when an exception is thrown during an asynchronous operation.\r
+        /// </summary>\r
+        /// <param name="exception">The exception that was thrown.</param>\r
+        /// <param name="networkGame">The NetworkGame that errored.</param>\r
+        public delegate void CaughtErrorDelegate(Exception exception, NetworkManager networkGame);\r
+\r
+        /// <summary>\r
+        /// Get and set the error delegate, called when an exception is thrown during\r
+        /// and asynchronous operation.  This will occur if you try to create or join a\r
+        /// session without being logged into a profile.\r
+        /// </summary>\r
+        public CaughtErrorDelegate ErrorDelegate;\r
+\r
+\r
+        /// <summary>\r
+        /// Construct a NetworkGame with a lobby and a game.\r
+        /// </summary>\r
+        /// <param name="lobby">Provides an associated lobby to update and draw.</param>\r
+        /// <param name="game">Provides a game object to be played over the network.</param>\r
+        public NetworkManager(IScreenManager lobby, IDeterministicGame game)\r
+        {\r
+            Debug.Assert(lobby != null && game != null);\r
+\r
+            mLobby = lobby;\r
+            mGame = game;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Get the Gamer object for the local player.\r
+        /// </summary>\r
+        public LocalNetworkGamer LocalGamer\r
+        {\r
+            get\r
+            {\r
+                // TODO: Is this the correct way to get the single local gamer?\r
+                return mNetworkSession.LocalGamers[0];\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get all the gamers associated with the active network session.\r
+        /// </summary>\r
+        public GamerCollection<NetworkGamer> NetworkGamers\r
+        {\r
+            get\r
+            {\r
+                return mNetworkSession.AllGamers;\r
+            }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Begin a new network session with the local gamer as the host.  You must not\r
+        /// call this method or use JoinSession without first using LeaveSession.\r
+        /// </summary>\r
+        /// <param name="callback">The delegate/method to call when the session is created.</param>\r
+        public void CreateSession(JoinedSessionDelegate callback)\r
+        {\r
+            CreateSession(mGame.MaximumSupportedPlayers, callback);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Begin a new network session with the local gamer as the host.  You must not\r
+        /// call this method or use JoinSession without first using LeaveSession.\r
+        /// </summary>\r
+        /// <param name="maxGamers">Provide the maximum number of players allowed to connect.</param>\r
+        /// <param name="callback">The delegate/method to call when the session is created.</param>\r
+        public void CreateSession(int maxGamers, JoinedSessionDelegate callback)\r
+        {\r
+            Debug.Assert(mNetworkSession == null);\r
+\r
+            mJoinedSessionDelegate = callback;\r
+            NetworkSession.BeginCreate(NetworkSessionType.SystemLink, 1, maxGamers, CreateSessionEnd, null);\r
+        }\r
+        void CreateSessionEnd(IAsyncResult result)\r
+        {\r
+            Debug.Assert(mNetworkSession == null);\r
+\r
+            try\r
+            {\r
+                mNetworkSession = NetworkSession.EndCreate(result);\r
+                mNetworkSession.AllowHostMigration = true;\r
+                mNetworkSession.AllowJoinInProgress = false;\r
+                mNetworkSession.GameStarted += new EventHandler<GameStartedEventArgs>(GameStartedEvent);\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                if (ErrorDelegate != null) ErrorDelegate(e, this);\r
+                return;\r
+            }\r
+            mJoinedSessionDelegate(mNetworkSession, this);\r
+            mJoinedSessionDelegate = null;\r
+        }\r
+        void GameStartedEvent(object sender, GameStartedEventArgs e)\r
+        {\r
+            Reset();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Determine whether or not the network game object is associated with any network session.\r
+        /// </summary>\r
+        /// <returns>True if there exists a NetworkSession; false otherwise.</returns>\r
+        public bool HasActiveSession\r
+        {\r
+            get\r
+            {\r
+                return mNetworkSession != null;\r
+            }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Find available sessions to join.  You should not already be in a session when\r
+        /// calling this method; call LeaveSession first.\r
+        /// </summary>\r
+        /// <param name="callback">The delegate/method to call when the search finishes.</param>\r
+        public void FindSessions(FoundSessionsDelegate callback)\r
+        {\r
+            Debug.Assert(mNetworkSession == null);\r
+\r
+            mFoundSessionsDelegate = callback;\r
+            NetworkSession.BeginFind(NetworkSessionType.SystemLink, 1, null, new AsyncCallback(FindSessionsEnd), null);\r
+        }\r
+        void FindSessionsEnd(IAsyncResult result)\r
+        {\r
+            AvailableNetworkSessionCollection sessions;\r
+            try\r
+            {\r
+                sessions = NetworkSession.EndFind(result);\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                if (ErrorDelegate != null) ErrorDelegate(e, this);\r
+                return;\r
+            }\r
+            mFoundSessionsDelegate(sessions, this);\r
+            mFoundSessionsDelegate = null;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Join a network session found using FindSessions().  This is for joining a game that\r
+        /// somebody else has already started hosting.  You must not already be in a session.\r
+        /// </summary>\r
+        /// <param name="availableSession">Pass the session object to try to join.</param>\r
+        /// <param name="callback">The delegate/method to call when the search finishes.</param>\r
+        public void JoinSession(AvailableNetworkSession availableSession, JoinedSessionDelegate callback)\r
+        {\r
+            Debug.Assert(mNetworkSession == null);\r
+\r
+            mJoinedSessionDelegate = callback;\r
+            NetworkSession.BeginJoin(availableSession, JoinSessionEnd, null);\r
+        }\r
+        void JoinSessionEnd(IAsyncResult result)\r
+        {\r
+            Debug.Assert(mNetworkSession == null);\r
+\r
+            try\r
+            {\r
+                mNetworkSession = NetworkSession.EndJoin(result);\r
+                mNetworkSession.GameStarted += new EventHandler<GameStartedEventArgs>(GameStartedEvent);\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                if (ErrorDelegate != null) ErrorDelegate(e, this);\r
+                return;\r
+            }\r
+            mJoinedSessionDelegate(mNetworkSession, this);\r
+            mJoinedSessionDelegate = null;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Leave and dispose of any currently associated network session.  You will find yourself\r
+        /// back in the lobby.  You must already be in a session to leave it.\r
+        /// </summary>\r
+        public void LeaveSession()\r
+        {\r
+            Debug.Assert(mNetworkSession != null);\r
+\r
+            mNetworkSession.Dispose();\r
+            mNetworkSession = null;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Set up the network session to simulate 200ms latency and 10% packet loss.\r
+        /// </summary>\r
+        public void SimulateBadNetwork()\r
+        {\r
+            Debug.Assert(mNetworkSession != null);\r
+\r
+            mNetworkSession.SimulatedLatency = new TimeSpan(0, 0, 0, 0, 200);\r
+            mNetworkSession.SimulatedPacketLoss = 0.1f;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Indicate that the game should begin (moving players from the lobby to the game).\r
+        /// You must call CreateSession() before calling this.\r
+        /// </summary>\r
+        public void StartGame()\r
+        {\r
+            Debug.Assert(mNetworkSession != null && mNetworkSession.IsHost &&\r
+                         mNetworkSession.AllGamers.Count >= mGame.MinimumSupportedPlayers &&\r
+                         mNetworkSession.IsEveryoneReady);\r
+\r
+            ForceStartGame();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Indicate that the game should begin.  This is like StartGame() without the sanity\r
+        /// checks.  Use this for debugging.\r
+        /// </summary>\r
+        public void ForceStartGame()\r
+        {\r
+            mNetworkSession.StartGame();\r
+            mNetworkSession.ResetReady();\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Manages the network session and allows either the lobby or game to update.\r
+        /// </summary>\r
+        /// <param name="gameTime">Pass the time away.</param>\r
+        public void Update(GameTime gameTime)\r
+        {\r
+            if (mNetworkSession == null)\r
+            {\r
+                mLobby.Update(gameTime, this);\r
+            }\r
+            else\r
+            {\r
+                mNetworkSession.Update();\r
+                HandleIncomingPackets();\r
+\r
+                if (mNetworkSession.SessionState == NetworkSessionState.Lobby)\r
+                {\r
+                    mLobby.Update(gameTime, this);\r
+                }\r
+                else if (mNetworkSession.SessionState == NetworkSessionState.Playing)\r
+                {\r
+                    if (mGame.IsTerminated(LocalGamerInfo))\r
+                    {\r
+                        LeaveSession();\r
+                        return;\r
+                    }\r
+                    else if (mGame.IsGameOver(LocalGamerInfo))\r
+                    {\r
+                        ApplyEvents(LocalGamerInfo, GetEventsFromInput());\r
+                        mGame.Update(mTargetTimeSpan);\r
+                        return;\r
+                    }\r
+\r
+                    if (HaveNeededEvents)\r
+                    {\r
+                        if (IsLatencyAdjustmentFrame)\r
+                        {\r
+                            AdjustLatency();\r
+                            mLastStallCount = mStallCount;\r
+                            mStallCount = 0;\r
+                        }\r
+                        mLocalEvents.AddRange(GetEventsFromInput());\r
+                        SendLocalEvents();\r
+                        ApplyEvents();\r
+\r
+#if DEBUG\r
+                        Console.WriteLine("HASH: " + mGame.CurrentFrameNumber + "\t" + mGame.CurrentChecksum);\r
+#endif\r
+\r
+                        mGame.Update(mTargetTimeSpan);\r
+                    }\r
+                    else // Stall!\r
+                    {\r
+                        mStallCount++;\r
+\r
+                        // Send a reliable event packet to each stalled gamer.\r
+                        if (mStallCount == 1)\r
+                        {\r
+#if DEBUG\r
+                            Console.WriteLine("STAL: ====");\r
+#endif\r
+\r
+                            foreach (GamerInfo gamerInfo in GamerArray)\r
+                            {\r
+                                if (gamerInfo.HighestFrameNumber < mGame.CurrentFrameNumber)\r
+                                {\r
+                                    SendLocalEvents(gamerInfo.Gamer);\r
+                                }\r
+                            }\r
+                        }\r
+                        else if (mStallCount > 600)\r
+                        {\r
+                            Console.WriteLine("One or more players have stalled excessively.  Leaving session...");\r
+                            LeaveSession();\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Allows either the lobby or the game to draw, depending on the state\r
+        /// of the network connection and whether or not a game is in progress.\r
+        /// </summary>\r
+        /// <param name="gameTime">Pass the time away.</param>\r
+        /// <param name="spriteBatch">The sprite batch.</param>\r
+        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)\r
+        {\r
+            if (mNetworkSession == null)\r
+            {\r
+                mLobby.Draw(spriteBatch);\r
+            }\r
+            else\r
+            {\r
+                if (mNetworkSession.SessionState == NetworkSessionState.Lobby)\r
+                {\r
+                    mLobby.Draw(spriteBatch);\r
+                }\r
+                else if (mNetworkSession.SessionState == NetworkSessionState.Playing)\r
+                {\r
+                    mGame.Draw(spriteBatch);\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Get the chat messages that have been received since the last time this\r
+        /// method was called.\r
+        /// </summary>\r
+        /// <returns>List container of the chat messages.</returns>\r
+        public List<ChatInfo> ReceiveChats()\r
+        {\r
+            List<ChatInfo> chats = mChatPackets;\r
+            mChatPackets = new List<ChatInfo>();\r
+            return chats;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Send a chat message to all gamers in the session.  You should already be\r
+        /// in a session before calling this method.\r
+        /// </summary>\r
+        /// <param name="message">The text of the message.</param>\r
+        public void SendChat(String message)\r
+        {\r
+            WriteChatPacket(message);\r
+            LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Send a chat message to a specific gamer in the session.  You should already\r
+        /// be in a session before calling this method.\r
+        /// </summary>\r
+        /// <param name="message">The text of the message.</param>\r
+        /// <param name="recipient">The gamer to receive the message.</param>\r
+        public void SendChat(String message, NetworkGamer recipient)\r
+        {\r
+            Debug.Assert(recipient != null && !recipient.IsDisposed);\r
+\r
+            WriteChatPacket(message);\r
+            LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder, recipient);\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        // Private class variable members\r
+        #region Instance Variables\r
+\r
+        NetworkSession mNetworkSession;\r
+        PacketReader mPacketReader = new PacketReader();\r
+        PacketWriter mPacketWriter = new PacketWriter();\r
+\r
+        JoinedSessionDelegate mJoinedSessionDelegate;\r
+        FoundSessionsDelegate mFoundSessionsDelegate;\r
+\r
+        IScreenManager mLobby;\r
+        IDeterministicGame mGame;\r
+\r
+        List<ChatInfo> mChatPackets = new List<ChatInfo>();\r
+\r
+        List<EventInfo> mLocalEvents = new List<EventInfo>();\r
+        List<EventInfo> mLastLocalEvents = new List<EventInfo>();\r
+\r
+        List<Keys> mLastPressedKeys = new List<Keys>();\r
+        bool mLastLeftButtonPressed;\r
+        bool mLastRightButtonPressed;\r
+        bool mLastMiddleButtonPressed;\r
+        int mLastMousePositionX;\r
+        int mLastMousePositionY;\r
+\r
+        int mLatency;\r
+        long mHighestFrameNumber;\r
+        long mNextLatencyAdjustmentFrame;\r
+        int mStallCount;\r
+        int mLastStallCount;\r
+        int mAverageOwd;\r
+\r
+#if DEBUG\r
+        bool mDontSendEvents;\r
+#endif\r
+\r
+        TimeSpan mTargetTimeSpan = new TimeSpan(166666);\r
+        public TimeSpan TargetTimeSpan\r
+        {\r
+            get\r
+            {\r
+                return mTargetTimeSpan;\r
+            }\r
+        }\r
+\r
+        Dictionary<byte, GamerInfo> mGamers;\r
+        GamerInfo[] GamerArray\r
+        {\r
+            get\r
+            {\r
+                GamerInfo[] gamerList = mGamers.Values.ToArray();\r
+                Array.Sort(gamerList, delegate(GamerInfo a, GamerInfo b)\r
+                {\r
+                    return a.Gamer.Id.CompareTo(b.Gamer.Id);\r
+                });\r
+                return gamerList;\r
+            }\r
+        }\r
+        GamerInfo LocalGamerInfo\r
+        {\r
+            get\r
+            {\r
+                return mGamers[LocalGamer.Id];\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        // Private types for the implementation of the network protocol\r
+        #region Private Types\r
+        \r
+        enum PacketType\r
+        {\r
+            Chat = 1,\r
+            Event = 2\r
+        }\r
+\r
+        enum EventType\r
+        {\r
+            KeyDown = 1,\r
+            KeyUp = 2,\r
+            MouseDown = 3,\r
+            MouseUp = 4,\r
+            MouseMove = 5\r
+        }\r
+\r
+        enum MouseButton\r
+        {\r
+            Left = 1,\r
+            Right = 2,\r
+            Middle = 3\r
+        }\r
+\r
+        abstract class EventInfo\r
+        {\r
+            public NetworkGamer Gamer;\r
+            public long FrameOfApplication;\r
+\r
+            public EventInfo(NetworkGamer gamer, long frameNumber)\r
+            {\r
+                Gamer = gamer;\r
+                FrameOfApplication = frameNumber;\r
+            }\r
+\r
+            public abstract EventType Id\r
+            {\r
+                get;\r
+            }\r
+        }\r
+\r
+        class KeyboardEventInfo : EventInfo\r
+        {\r
+            public Keys Key;\r
+            public bool IsKeyDown;\r
+\r
+            public KeyboardEventInfo(NetworkGamer gamer, long frameNumber, Keys key, bool isDown)\r
+                : base(gamer, frameNumber)\r
+            {\r
+                Key = key;\r
+                IsKeyDown = isDown;\r
+            }\r
+\r
+            public override EventType Id\r
+            {\r
+                get { return IsKeyDown ? EventType.KeyDown : EventType.KeyUp; }\r
+            }\r
+        }\r
+\r
+        class MouseButtonEventInfo : EventInfo\r
+        {\r
+            public MouseButton Button;\r
+            public bool IsButtonDown;\r
+\r
+            public MouseButtonEventInfo(NetworkGamer gamer, long frameNumber, MouseButton button, bool isDown)\r
+                : base(gamer, frameNumber)\r
+            {\r
+                Button = button;\r
+                IsButtonDown = isDown;\r
+            }\r
+\r
+            public override EventType Id\r
+            {\r
+                get { return IsButtonDown ? EventType.MouseDown : EventType.MouseUp; }\r
+            }\r
+        }\r
+\r
+        class MouseMotionEventInfo : EventInfo\r
+        {\r
+            public int X;\r
+            public int Y;\r
+\r
+            public MouseMotionEventInfo(NetworkGamer gamer, long frameNumber, int x, int y)\r
+                : base(gamer, frameNumber)\r
+            {\r
+                X = x;\r
+                Y = y;\r
+            }\r
+\r
+            public override EventType Id\r
+            {\r
+                get { return EventType.MouseMove; }\r
+            }\r
+        }\r
+\r
+        class GamerInfo\r
+        {\r
+            public NetworkGamer Gamer;\r
+            public long HighestFrameNumber = 0;\r
+            public int StallCount = 0;\r
+            public int AverageOwd = 0;\r
+            public int NextStallCount = 0;\r
+            public int NextAverageOwd = 0;\r
+            public bool IsWaitedOn = false;\r
+            public List<EventInfo>[] Events = new List<EventInfo>[MaximumLatency];\r
+\r
+            public GamerInfo(NetworkGamer gamer)\r
+            {\r
+                Gamer = gamer;\r
+            }\r
+        }\r
+\r
+        const int MaximumLatency = 120;\r
+        const int StallTimeout = 900;\r
+\r
+        #endregion\r
+\r
+\r
+        // Private implementation methods of the network protocol\r
+        #region Private Implementation Methods\r
+\r
+        /// <summary>\r
+        /// Reinitialize the private variables in preparation for a new game to start.\r
+        /// </summary>\r
+        void Reset()\r
+        {\r
+            mLatency = 1;\r
+            mHighestFrameNumber = 0;\r
+            mNextLatencyAdjustmentFrame = 1;\r
+            mStallCount = 0;\r
+            mLastStallCount = 0;\r
+            mAverageOwd = CurrentAverageOneWayDelay;\r
+\r
+            mGamers = new Dictionary<byte, GamerInfo>();\r
+            foreach (NetworkGamer gamer in NetworkGamers)\r
+            {\r
+                mGamers.Add(gamer.Id, new GamerInfo(gamer));\r
+            }\r
+\r
+            mGame.ResetGame(GamerArray, LocalGamerInfo);\r
+        }\r
+\r
+\r
+        void HandleIncomingPackets()\r
+        {\r
+            LocalNetworkGamer localGamer = LocalGamer;\r
+\r
+            while (localGamer.IsDataAvailable)\r
+            {\r
+                NetworkGamer sender;\r
+\r
+                localGamer.ReceiveData(mPacketReader, out sender);\r
+\r
+                PacketType packetId = (PacketType)mPacketReader.ReadByte();\r
+                switch (packetId)\r
+                {\r
+                    case PacketType.Chat:\r
+\r
+                        short messageLength = mPacketReader.ReadInt16();\r
+                        char[] message = mPacketReader.ReadChars(messageLength);\r
+\r
+                        ChatInfo chatPacket = new ChatInfo(sender, new String(message));\r
+                        mChatPackets.Add(chatPacket);\r
+                        break;\r
+\r
+                    case PacketType.Event:\r
+\r
+                        GamerInfo senderInfo = mGamers[sender.Id];\r
+\r
+                        int stallCount = mPacketReader.ReadInt16();\r
+                        int averageOwd = mPacketReader.ReadInt16();\r
+                        int frameNumber = mPacketReader.ReadInt32();\r
+                        int numEvents = mPacketReader.ReadByte();\r
+\r
+                        if (frameNumber <= mNextLatencyAdjustmentFrame)\r
+                        {\r
+                            senderInfo.StallCount = stallCount;\r
+                            senderInfo.AverageOwd = averageOwd;\r
+                        }\r
+                        else\r
+                        {\r
+                            senderInfo.NextStallCount = stallCount;\r
+                            senderInfo.NextAverageOwd = averageOwd;\r
+                        }\r
+\r
+                        if (frameNumber <= senderInfo.HighestFrameNumber)\r
+                        {\r
+#if DEBUG\r
+                            Console.WriteLine("SKP" + (char)sender.Id + ": " + mGame.CurrentFrameNumber + "\t" + frameNumber + "\t<=\t" + senderInfo.HighestFrameNumber + "\t#" + numEvents);\r
+#endif\r
+\r
+                            // we know about all these events, so don't bother reading them\r
+                            break;\r
+                        }\r
+\r
+#if DEBUG\r
+                        Console.WriteLine(" GOT" + (char)sender.Id + ": " + mGame.CurrentFrameNumber + "\t" + frameNumber + "\t>\t" + senderInfo.HighestFrameNumber + "\t#" + numEvents);\r
+#endif\r
+\r
+                        for (int i = 0; i < numEvents; i++)\r
+                        {\r
+                            EventInfo eventInfo = ReadEvent(mPacketReader, sender);\r
+                            \r
+                            if (eventInfo != null && eventInfo.FrameOfApplication > senderInfo.HighestFrameNumber)\r
+                            {\r
+                                int index = GetEventArrayIndexForFrame(eventInfo.FrameOfApplication);\r
+                                if (senderInfo.Events[index] == null) senderInfo.Events[index] = new List<EventInfo>();\r
+                                senderInfo.Events[index].Add(eventInfo);\r
+                            }\r
+                        }\r
+\r
+                        senderInfo.HighestFrameNumber = frameNumber;\r
+                        break;\r
+\r
+                    default:\r
+\r
+                        Console.WriteLine("Received unknown packet type: " + (int)packetId);\r
+                        break;\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        int CurrentEventArrayIndex\r
+        {\r
+            get { return GetEventArrayIndexForFrame(mGame.CurrentFrameNumber); }\r
+        }\r
+\r
+        int GetEventArrayIndexForFrame(long frame)\r
+        {\r
+            return (int)(frame % MaximumLatency);\r
+        }\r
+\r
+        EventInfo ReadEvent(PacketReader packetReader, NetworkGamer sender)\r
+        {\r
+            EventType eventId = (EventType)packetReader.ReadByte();\r
+            long frameNumber = packetReader.ReadInt32();\r
+\r
+            switch (eventId)\r
+            {\r
+                case EventType.KeyDown:\r
+\r
+                    Keys keyCode1 = (Keys)packetReader.ReadInt32();\r
+                    return new KeyboardEventInfo(sender, frameNumber, keyCode1, true);\r
+\r
+                case EventType.KeyUp:\r
+\r
+                    Keys keyCode2 = (Keys)packetReader.ReadInt32();\r
+                    return new KeyboardEventInfo(sender, frameNumber, keyCode2, false);\r
+\r
+                case EventType.MouseDown:\r
+\r
+                    MouseButton buttonId1 = (MouseButton)packetReader.ReadByte();\r
+                    return new MouseButtonEventInfo(sender, frameNumber, buttonId1, true);\r
+\r
+                case EventType.MouseUp:\r
+\r
+                    MouseButton buttonId2 = (MouseButton)packetReader.ReadByte();\r
+                    return new MouseButtonEventInfo(sender, frameNumber, buttonId2, false);\r
+\r
+                case EventType.MouseMove:\r
+\r
+                    short x = packetReader.ReadInt16();\r
+                    short y = packetReader.ReadInt16();\r
+                    return new MouseMotionEventInfo(sender, frameNumber, x, y);\r
+\r
+                default:\r
+\r
+                    Console.WriteLine("Received unknown event type: " + (int)eventId);\r
+                    return null;\r
+            }\r
+        }\r
+\r
+\r
+        void WriteChatPacket(String message)\r
+        {\r
+            mPacketWriter.Write((byte)PacketType.Chat);\r
+            mPacketWriter.Write((short)message.Length);\r
+            mPacketWriter.Write(message.ToCharArray());\r
+        }\r
+\r
+        void WriteEventPacket(List<EventInfo> events, long highestFrameNumber)\r
+        {\r
+            mPacketWriter.Write((byte)PacketType.Event);\r
+            mPacketWriter.Write((short)mLastStallCount);\r
+            mPacketWriter.Write((short)mAverageOwd);\r
+            mPacketWriter.Write((int)highestFrameNumber);\r
+            mPacketWriter.Write((byte)events.Count);\r
+\r
+            foreach (EventInfo eventInfo in events)\r
+            {\r
+                mPacketWriter.Write((byte)eventInfo.Id);\r
+                mPacketWriter.Write((int)eventInfo.FrameOfApplication);\r
+\r
+                KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;\r
+                if (keyboardEventInfo != null)\r
+                {\r
+                    mPacketWriter.Write((int)keyboardEventInfo.Key);\r
+                    continue;\r
+                }\r
+\r
+                MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;\r
+                if (mouseButtonEventInfo != null)\r
+                {\r
+                    mPacketWriter.Write((byte)mouseButtonEventInfo.Button);\r
+                    continue;\r
+                }\r
+\r
+                MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;\r
+                if (mouseMotionEventInfo != null)\r
+                {\r
+                    mPacketWriter.Write((short)mouseMotionEventInfo.X);\r
+                    mPacketWriter.Write((short)mouseMotionEventInfo.Y);\r
+                    continue;\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        bool IsLatencyAdjustmentFrame\r
+        {\r
+            get\r
+            {\r
+                return mNextLatencyAdjustmentFrame == mGame.CurrentFrameNumber;\r
+            }\r
+        }\r
+\r
+        void AdjustLatency()\r
+        {\r
+            Debug.Assert(IsLatencyAdjustmentFrame);\r
+\r
+#if DEBUG\r
+            if (mStallCount > 0)\r
+            {\r
+                Console.WriteLine("STL#: " + mGame.CurrentFrameNumber + "\t" + mStallCount);\r
+            }\r
+#endif\r
+\r
+            int maxStallCount = 0;\r
+            int maxAverageOwd = 0;\r
+\r
+            foreach (GamerInfo gamerInfo in GamerArray)\r
+            {\r
+                if (gamerInfo.StallCount > maxStallCount) maxStallCount = gamerInfo.StallCount;\r
+                if (gamerInfo.AverageOwd > maxAverageOwd) maxAverageOwd = gamerInfo.AverageOwd;\r
+\r
+                gamerInfo.StallCount = gamerInfo.NextStallCount;\r
+                gamerInfo.AverageOwd = gamerInfo.NextAverageOwd;\r
+            }\r
+\r
+#if DEBUG\r
+            int prevLatency = mLatency;\r
+#endif\r
+\r
+            if (maxStallCount > 0)\r
+            {\r
+                mLatency += maxStallCount;\r
+            }\r
+            else\r
+            {\r
+                mLatency -= (int)(0.6 * (double)(mLatency - maxAverageOwd) + 1.0);\r
+            }\r
+\r
+            if (mLatency < 1) mLatency = 1;\r
+            if (mLatency > MaximumLatency) mLatency = MaximumLatency;\r
+\r
+#if DEBUG\r
+            if (prevLatency != mLatency) Console.WriteLine("NLAG: " + mLatency);\r
+#endif\r
+\r
+            mNextLatencyAdjustmentFrame = mGame.CurrentFrameNumber + mLatency;\r
+            mAverageOwd = CurrentAverageOneWayDelay;\r
+\r
+            mLastLocalEvents = mLocalEvents;\r
+            mLocalEvents = new List<EventInfo>();\r
+        }\r
+\r
+\r
+\r
+        List<EventInfo> GetEventsFromInput()\r
+        {\r
+            List<EventInfo> events = new List<EventInfo>();\r
+\r
+            long frameOfApplication = mGame.CurrentFrameNumber + mLatency;\r
+            if (frameOfApplication <= mHighestFrameNumber) return events;\r
+            else mHighestFrameNumber = frameOfApplication;\r
+\r
+            // 1. Find the keyboard differences; written by Peter.\r
+\r
+            KeyboardState keyState = Keyboard.GetState();\r
+\r
+            List<Keys> pressedKeys = new List<Keys>();\r
+            List<Keys> releasedKeys = new List<Keys>();\r
+\r
+            Keys[] pressedKeysArray = keyState.GetPressedKeys();\r
+            foreach (Keys k in pressedKeysArray)\r
+            {\r
+                if (!mLastPressedKeys.Contains(k)) pressedKeys.Add(k);\r
+                else mLastPressedKeys.Remove(k);\r
+            }\r
+\r
+            releasedKeys = mLastPressedKeys;\r
+\r
+            foreach (Keys key in pressedKeys)\r
+            {\r
+                events.Add(new KeyboardEventInfo(LocalGamer, frameOfApplication, key, true));\r
+            }\r
+            foreach (Keys key in releasedKeys)\r
+            {\r
+                events.Add(new KeyboardEventInfo(LocalGamer, frameOfApplication, key, false));\r
+            }\r
+\r
+#if DEBUG\r
+            if (pressedKeys.Contains(Keys.Escape)) mDontSendEvents = true;\r
+            if (releasedKeys.Contains(Keys.Escape)) mDontSendEvents = false;\r
+#endif\r
+\r
+            // 2. Find the mouse differences.\r
+\r
+            MouseState mouseState = Mouse.GetState();\r
+\r
+            bool leftButtonPressed = mouseState.LeftButton == ButtonState.Pressed;\r
+            if (leftButtonPressed != mLastLeftButtonPressed)\r
+            {\r
+                events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Left, leftButtonPressed));\r
+            }\r
+\r
+            bool rightButtonPressed = mouseState.RightButton == ButtonState.Pressed;\r
+            if (rightButtonPressed != mLastRightButtonPressed)\r
+            {\r
+                events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Right, rightButtonPressed));\r
+            }\r
+\r
+            bool middleButtonPressed = mouseState.MiddleButton == ButtonState.Pressed;\r
+            if (middleButtonPressed != mLastMiddleButtonPressed)\r
+            {\r
+                events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Middle, middleButtonPressed));\r
+            }\r
+\r
+            int mousePositionX = mouseState.X;\r
+            int mousePositionY = mouseState.Y;\r
+            if (mousePositionX != mLastMousePositionX || mousePositionY != mLastMousePositionY)\r
+            {\r
+                events.Add(new MouseMotionEventInfo(LocalGamer, frameOfApplication, mousePositionX, mousePositionY));\r
+            }\r
+\r
+            // 3. Save the current peripheral state.\r
+\r
+            mLastPressedKeys = new List<Keys>(pressedKeysArray);\r
+            mLastLeftButtonPressed = leftButtonPressed;\r
+            mLastRightButtonPressed = rightButtonPressed;\r
+            mLastMiddleButtonPressed = middleButtonPressed;\r
+            mLastMousePositionX = mousePositionX;\r
+            mLastMousePositionY = mousePositionY;\r
+\r
+            return events;\r
+        }\r
+\r
+        void SendLocalEvents()\r
+        {\r
+            SendLocalEvents((NetworkGamer)null);\r
+        }\r
+\r
+        void SendLocalEvents(List<NetworkGamer> recipicents)\r
+        {\r
+            foreach (NetworkGamer gamer in recipicents)\r
+            {\r
+                SendLocalEvents(gamer);\r
+            }\r
+        }\r
+\r
+        void SendLocalEvents(NetworkGamer recipient)\r
+        {\r
+#if DEBUG\r
+            if (mDontSendEvents) return;\r
+#endif\r
+\r
+            List<EventInfo> events = new List<EventInfo>(mLocalEvents);\r
+            events.AddRange(mLastLocalEvents);\r
+\r
+            if (recipient != null && !recipient.IsDisposed)\r
+            {\r
+                // if there is a recipient, we are resending old events\r
+                WriteEventPacket(events, mGame.CurrentFrameNumber - 1);\r
+                LocalGamer.SendData(mPacketWriter, SendDataOptions.Reliable, recipient);\r
+            }\r
+            else\r
+            {\r
+                WriteEventPacket(events, mGame.CurrentFrameNumber + mLatency);\r
+                LocalGamer.SendData(mPacketWriter, SendDataOptions.None);\r
+            }\r
+        }\r
+\r
+\r
+        bool HaveNeededEvents\r
+        {\r
+            get\r
+            {\r
+                long currentFrame = mGame.CurrentFrameNumber;\r
+\r
+                foreach (GamerInfo gamerInfo in mGamers.Values)\r
+                {\r
+                    if (mGame.IsGameOver(gamerInfo)) continue;\r
+                    if (gamerInfo.HighestFrameNumber < currentFrame) return false;\r
+                }\r
+\r
+                return true;\r
+            }\r
+        }\r
+\r
+        void ApplyEvents()\r
+        {\r
+            int index = CurrentEventArrayIndex;\r
+\r
+            foreach (GamerInfo gamerInfo in GamerArray)\r
+            {\r
+                if (gamerInfo.Events[index] == null) continue;\r
+                ApplyEvents(gamerInfo, gamerInfo.Events[index]);\r
+                gamerInfo.Events[index] = null;\r
+            }\r
+        }\r
+\r
+        void ApplyEvents(GamerInfo gamerInfo, List<EventInfo> events)\r
+        {\r
+            foreach (EventInfo eventInfo in events)\r
+            {\r
+                KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;\r
+                if (keyboardEventInfo != null)\r
+                {\r
+#if DEBUG\r
+                    Console.WriteLine(" KEY: " + keyboardEventInfo.FrameOfApplication + "\t" + keyboardEventInfo.Key + "," + keyboardEventInfo.IsKeyDown);\r
+#endif\r
+\r
+                    mGame.ApplyKeyInput(gamerInfo, keyboardEventInfo.Key, keyboardEventInfo.IsKeyDown);\r
+                    continue;\r
+                }\r
+\r
+                MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;\r
+                if (mouseButtonEventInfo != null)\r
+                {\r
+#if DEBUG\r
+                    Console.WriteLine(" BTN: " + mouseButtonEventInfo.FrameOfApplication + "\t" + mouseButtonEventInfo.IsButtonDown);\r
+#endif\r
+\r
+                    mGame.ApplyMouseButtonInput(gamerInfo, mouseButtonEventInfo.IsButtonDown);\r
+                    continue;\r
+                }\r
+\r
+                MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;\r
+                if (mouseMotionEventInfo != null)\r
+                {\r
+#if DEBUG\r
+                    Console.WriteLine(" MMV: " + mouseMotionEventInfo.FrameOfApplication + "\t" + mouseMotionEventInfo.X + "," + mouseMotionEventInfo.Y);\r
+#endif\r
+\r
+                    mGame.ApplyMouseLocationInput(gamerInfo, mouseMotionEventInfo.X, mouseMotionEventInfo.Y);\r
+                    continue;\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        int CurrentAverageOneWayDelay\r
+        {\r
+            get\r
+            {\r
+                Debug.Assert(mNetworkSession != null);\r
+\r
+                double numRemoteGamersTwice = 2 * mNetworkSession.RemoteGamers.Count;\r
+                double averageOwd = 0;\r
+\r
+                foreach (NetworkGamer gamer in mNetworkSession.RemoteGamers)\r
+                {\r
+                    TimeSpan timeSpan = gamer.RoundtripTime;\r
+                    averageOwd += timeSpan.TotalMilliseconds;\r
+                }\r
+\r
+                return (int)((averageOwd / numRemoteGamersTwice) / 16.6666);\r
+            }\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}\r
index 7dad1ae6e185011dbf080baf5bd386a01b364da5..8a008959c5b98101841f728aed55d6d61a02a8b5 100644 (file)
@@ -9,7 +9,7 @@ namespace CarFire
         /// </summary>\r
         static void Main(string[] args)\r
         {\r
-            using (Game1 game = new Game1())\r
+            using (XnaGame game = new XnaGame())\r
             {\r
                 game.Run();\r
             }\r
diff --git a/CarFire/CarFire/CarFire/ScreenManager.cs b/CarFire/CarFire/CarFire/ScreenManager.cs
new file mode 100644 (file)
index 0000000..5c6bf71
--- /dev/null
@@ -0,0 +1,35 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+\r
+namespace CarFire\r
+{\r
+    class ScreenManager : IScreenManager\r
+    {\r
+        #region ILobby Members\r
+\r
+        public void LoadContent(ContentManager contentManager, GraphicsDeviceManager graphics)\r
+        {\r
+        }\r
+\r
+        public void UnloadContent()\r
+        {\r
+        }\r
+\r
+        public long Update(GameTime gameTime, NetworkManager networkGame)\r
+        {\r
+            return 0;\r
+        }\r
+\r
+        public long Draw(SpriteBatch spriteBatch)\r
+        {\r
+            return 0;\r
+        }\r
+\r
+        #endregion\r
+    }\r
+}\r
similarity index 65%
rename from CarFire/CarFire/CarFire/Game1.cs
rename to CarFire/CarFire/CarFire/XnaGame.cs
index 0b9d9fe372713c4b321a0e1841586c98688ed8a3..0623ae9f413b96f62555e2f648d2f373732ce99a 100644 (file)
@@ -16,15 +16,30 @@ namespace CarFire
     /// <summary>\r
     /// This is the main type for your game\r
     /// </summary>\r
-    public class Game1 : Microsoft.Xna.Framework.Game\r
+    public class XnaGame : Microsoft.Xna.Framework.Game\r
     {\r
         GraphicsDeviceManager graphics;\r
         SpriteBatch spriteBatch;\r
 \r
-        public Game1()\r
+        NetworkManager networkGame;\r
+        IScreenManager screenManager;\r
+        IDeterministicGame deterministicGame;\r
+\r
+        public XnaGame()\r
         {\r
             graphics = new GraphicsDeviceManager(this);\r
             Content.RootDirectory = "Content";\r
+\r
+            Components.Add(new GamerServicesComponent(this));\r
+\r
+            screenManager = new ScreenManager();\r
+            deterministicGame = new Game();\r
+            networkGame = new NetworkManager(screenManager, deterministicGame);\r
+\r
+            Vector2 size = deterministicGame.PreferredScreenSize;\r
+            graphics.PreferredBackBufferWidth = (int)size.X;\r
+            graphics.PreferredBackBufferHeight = (int)size.Y;\r
+            graphics.ApplyChanges();\r
         }\r
 \r
         /// <summary>\r
@@ -35,7 +50,8 @@ namespace CarFire
         /// </summary>\r
         protected override void Initialize()\r
         {\r
-            // TODO: Add your initialization logic here\r
+            IsFixedTimeStep = true;\r
+            TargetElapsedTime = networkGame.TargetTimeSpan;\r
 \r
             base.Initialize();\r
         }\r
@@ -49,7 +65,8 @@ namespace CarFire
             // Create a new SpriteBatch, which can be used to draw textures.\r
             spriteBatch = new SpriteBatch(GraphicsDevice);\r
 \r
-            // TODO: use this.Content to load your game content here\r
+            screenManager.LoadContent(Content, graphics);\r
+            deterministicGame.LoadContent(Content);\r
         }\r
 \r
         /// <summary>\r
@@ -58,7 +75,8 @@ namespace CarFire
         /// </summary>\r
         protected override void UnloadContent()\r
         {\r
-            // TODO: Unload any non ContentManager content here\r
+            screenManager.UnloadContent();\r
+            deterministicGame.UnloadContent();\r
         }\r
 \r
         /// <summary>\r
@@ -68,11 +86,7 @@ namespace CarFire
         /// <param name="gameTime">Provides a snapshot of timing values.</param>\r
         protected override void Update(GameTime gameTime)\r
         {\r
-            // Allows the game to exit\r
-            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)\r
-                this.Exit();\r
-\r
-            // TODO: Add your update logic here\r
+            networkGame.Update(gameTime);\r
 \r
             base.Update(gameTime);\r
         }\r
@@ -83,9 +97,11 @@ namespace CarFire
         /// <param name="gameTime">Provides a snapshot of timing values.</param>\r
         protected override void Draw(GameTime gameTime)\r
         {\r
-            GraphicsDevice.Clear(Color.CornflowerBlue);\r
+            GraphicsDevice.Clear(Color.Red);\r
 \r
-            // TODO: Add your drawing code here\r
+            spriteBatch.Begin();\r
+            networkGame.Draw(gameTime, spriteBatch);\r
+            spriteBatch.End();\r
 \r
             base.Draw(gameTime);\r
         }\r
This page took 0.055949 seconds and 4 git commands to generate.