]> Dogcows Code - chaz/carfire/commitdiff
Event packets implemented with complete latency readjusting.
authorCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Tue, 23 Mar 2010 20:57:42 +0000 (20:57 +0000)
committerCharles <Charles@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Tue, 23 Mar 2010 20:57:42 +0000 (20:57 +0000)
Testing with more than one player needed.

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

Project06/CS 3505 Project 06/CS 3505 Project 06/CS 3505 Project 06.csproj
Project06/CS 3505 Project 06/CS 3505 Project 06/CS 3505/TestHarness.cs
Project06/CS 3505 Project 06/CS 3505 Project 06/ChatInfo.cs [moved from Project06/CS 3505 Project 06/CS 3505 Project 06/ChatPacket.cs with 84% similarity]
Project06/CS 3505 Project 06/CS 3505 Project 06/Game06.cs
Project06/CS 3505 Project 06/CS 3505 Project 06/LobbyGUI.cs
Project06/CS 3505 Project 06/CS 3505 Project 06/NetworkGame.cs

index 99e7d27c2ff391ab17e1ef31d01883abccd81c59..cdf4d76ecc69d2fcc18740c1b0d2a214bf7ec17a 100644 (file)
@@ -84,7 +84,7 @@
     </Reference>\r
   </ItemGroup>\r
   <ItemGroup>\r
-    <Compile Include="ChatPacket.cs" />\r
+    <Compile Include="ChatInfo.cs" />\r
     <Compile Include="CS 3505\IDeterministicGame.cs" />\r
     <Compile Include="CS 3505\TestHarness.cs" />\r
     <Compile Include="ILobby.cs" />\r
index 76bc066fb1ba636bd2b2a19ef4dc0578cba89762..883e8a09676d15b86615d228fa0a7c12042118af 100644 (file)
@@ -224,12 +224,14 @@ namespace CS_3505_Project_06.CS_3505
 \r
         public void ResetGame(Object[] playerIdentifiers, Object thisPlayer)\r
         {\r
-            if (playerIdentifiers.Length != 4)\r
-                throw new Exception("This game requires four players.");\r
+            //if (playerIdentifiers.Length != 4)\r
+            //    throw new Exception("This game requires four players.");\r
 \r
             // Copy the player identifiers - do not rely on the array parameter not changing.\r
 \r
-            for (int i = 0; i < 4; i++)\r
+            // Now the test harness will at least run with less than 4 players...\r
+            int numPlayers = playerIdentifiers.Count();\r
+            for (int i = 0; i < numPlayers; i++)\r
                 this.playerIdentifiers[i] = playerIdentifiers[i];\r
 \r
             // Create new game state and inputs objects.\r
similarity index 84%
rename from Project06/CS 3505 Project 06/CS 3505 Project 06/ChatPacket.cs
rename to Project06/CS 3505 Project 06/CS 3505 Project 06/ChatInfo.cs
index 15e4470d888c3c8bc82d93c75e5fce211fea0205..39af42083eeec1f2a95f101e38f546d7cf25cf80 100644 (file)
@@ -10,7 +10,7 @@ namespace CS_3505_Project_06
     /// Small container class for the information concerning a chat packet.\r
     /// It is immutable.\r
     /// </summary>\r
-    public class ChatPacket\r
+    public class ChatInfo\r
     {\r
         // Private member variables\r
         #region Instance Variables\r
@@ -22,7 +22,7 @@ namespace CS_3505_Project_06
 \r
 \r
         /// <summary>\r
-        /// Get the game who sent the chat packet.\r
+        /// Get the sender who sent the chat packet.\r
         /// </summary>\r
         public NetworkGamer Sender\r
         {\r
@@ -43,7 +43,7 @@ namespace CS_3505_Project_06
         /// </summary>\r
         /// <param name="sender">The chat sender.</param>\r
         /// <param name="message">The chat message.</param>\r
-        public ChatPacket(NetworkGamer sender, String message)\r
+        public ChatInfo(NetworkGamer sender, String message)\r
         {\r
             mSender = sender;\r
             mMessage = message;\r
index 348655eeb07539f0128f2b4ece7c69a178a03d2b..8953452fba98ce55bd64c1d8c2bdf75b53a6dc87 100644 (file)
@@ -51,7 +51,6 @@ namespace CS_3505_Project_06
         protected override void Initialize()\r
         {\r
             // Set a fixed time span of 1/60th of a second.\r
-\r
             IsFixedTimeStep = true;\r
             TargetElapsedTime = networkGame.TargetTimeSpan;\r
 \r
@@ -59,7 +58,6 @@ namespace CS_3505_Project_06
             Mouse.SetPosition(400, 300);\r
 \r
             // Allow the base class to initialize.\r
-\r
             base.Initialize();\r
         }\r
 \r
index 3c157dc944b9042178446e385719cdcfb72451b7..4526befecb6c26ae2bf03441644bcf9324ccb016 100644 (file)
@@ -254,11 +254,11 @@ namespace CS_3505_Project_06
                         }\r
 \r
                         //allows host to start the game when all players are ready, change count below to different number for testing with less then 4 players\r
-                        if(allReady && players.Count == 2 && localPlayer == players[0])\r
+                        if(allReady && players.Count == 1 && localPlayer == players[0])\r
                         {\r
                             if (currentKeyboardState.IsKeyDown(Keys.B) && previousKeyboardState.IsKeyUp(Keys.B))\r
                             {\r
-                                networkGame.StartGame();\r
+                                networkGame.ForceStartGame();\r
                             }\r
                         }\r
                     }\r
index 03b6e90481812e40680b720009379c554f43b089..3ce0372be2059e941415307532a715ece59d8055 100644 (file)
@@ -8,6 +8,7 @@ using Microsoft.Xna.Framework.GamerServices;
 using Microsoft.Xna.Framework.Graphics;\r
 using Microsoft.Xna.Framework;\r
 using Microsoft.Xna.Framework.Input;\r
+using System.Collections;\r
 \r
 namespace CS_3505_Project_06\r
 {\r
@@ -17,6 +18,9 @@ namespace CS_3505_Project_06
     /// </summary>\r
     public class NetworkGame\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
@@ -190,10 +194,23 @@ namespace CS_3505_Project_06
         /// </summary>\r
         public void StartGame()\r
         {\r
-            Debug.Assert(mNetworkSession != null && mNetworkSession.IsHost);\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
+            Reset();\r
         }\r
 \r
 \r
@@ -210,34 +227,54 @@ namespace CS_3505_Project_06
             else\r
             {\r
                 mNetworkSession.Update();\r
-                ReadPackets();\r
+                HandleIncomingPackets();\r
 \r
                 if (mNetworkSession.SessionState == NetworkSessionState.Lobby)\r
                 {\r
-                    if (mNetworkSession.IsHost &&\r
-                        mNetworkSession.AllGamers.Count >= mGame.MinimumSupportedPlayers &&\r
-                        mNetworkSession.IsEveryoneReady)\r
-                    {\r
-                        mNetworkSession.StartGame();\r
-                        mNetworkSession.ResetReady();\r
-                    }\r
-                    else\r
-                    {\r
-                        mLobby.Update(gameTime, this);\r
-                    }\r
+                    mLobby.Update(gameTime, this);\r
                 }\r
                 else if (mNetworkSession.SessionState == NetworkSessionState.Playing)\r
                 {\r
+                    if (mGame.IsGameOver(LocalGamerInfo) || mGame.IsTerminated(LocalGamerInfo))\r
+                    {\r
+                        // TODO: Should support moving back to the session lobby.\r
+                        LeaveSession();\r
+                        return;\r
+                    }\r
+\r
                     if (HaveNeededEvents)\r
                     {\r
-                        if (IsLatencyAdjustmentFrame) AdjustLatency();\r
-                        mStallCount = 0;\r
+                        if (IsLatencyAdjustmentFrame)\r
+                        {\r
+                            AdjustLatency();\r
+                            mStallCount = 0;\r
+                        }\r
+                        mLocalEvents.AddRange(GetEventsFromInput());\r
                         SendLocalEvents();\r
                         ApplyEvents();\r
                         mGame.Update(mTargetTimeSpan);\r
                     }\r
                     else // Stall!\r
                     {\r
+                        mStallCount++;\r
+\r
+                        if (mStallCount % 60 == 0)\r
+                        {\r
+                            Console.WriteLine("Stalled for " + mStallCount + " frames.");\r
+                        }\r
+\r
+                        /*if (mStallCount > StallTimeout)\r
+                        {\r
+                            DropLostGamers();\r
+                            mStallCount = 0;\r
+                        }\r
+                        else if (mStallCount == 1)\r
+                        {\r
+                            SendLocalEvents\r
+                        }\r
+                        else if (mStallCount % 60 == 0)\r
+                        {\r
+                        } TODO */\r
                     }\r
                 }\r
             }\r
@@ -263,7 +300,7 @@ namespace CS_3505_Project_06
                 }\r
                 else if (mNetworkSession.SessionState == NetworkSessionState.Playing)\r
                 {\r
-                    mLobby.Draw(spriteBatch);\r
+                    mGame.Draw(spriteBatch);\r
                 }\r
             }\r
         }\r
@@ -274,10 +311,10 @@ namespace CS_3505_Project_06
         /// method was called.\r
         /// </summary>\r
         /// <returns>List container of the chat messages.</returns>\r
-        public List<ChatPacket> ReceiveChats()\r
+        public List<ChatInfo> ReceiveChats()\r
         {\r
-            List<ChatPacket> chats = mChatPackets;\r
-            mChatPackets = new List<ChatPacket>();\r
+            List<ChatInfo> chats = mChatPackets;\r
+            mChatPackets = new List<ChatInfo>();\r
             return chats;\r
         }\r
 \r
@@ -288,7 +325,7 @@ namespace CS_3505_Project_06
         /// <param name="message">The text of the message.</param>\r
         public void SendChat(String message)\r
         {\r
-            WriteChat(message);\r
+            WriteChatPacket(message);\r
             LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder);\r
         }\r
 \r
@@ -300,10 +337,12 @@ namespace CS_3505_Project_06
         /// <param name="recipient">The gamer to receive the message.</param>\r
         public void SendChat(String message, NetworkGamer recipient)\r
         {\r
-            WriteChat(message);\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
@@ -318,10 +357,17 @@ namespace CS_3505_Project_06
         ILobby mLobby;\r
         IDeterministicGame mGame;\r
 \r
-        List<ChatPacket> mChatPackets = new List<ChatPacket>();\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 mLastButtonPressed;\r
+        bool mLastLeftButtonPressed;\r
+        bool mLastRightButtonPressed;\r
+        bool mLastMiddleButtonPressed;\r
+        int mLastMousePositionX;\r
+        int mLastMousePositionY;\r
 \r
         int mLatency;\r
         long mNextLatencyAdjustmentFrame;\r
@@ -337,11 +383,32 @@ namespace CS_3505_Project_06
             }\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 implementation methods of the network protocol\r
-        #region Private Implementation Methods\r
+        // Private types for the implementation of the network protocol\r
+        #region Private Types\r
         \r
         enum PacketType\r
         {\r
@@ -359,161 +426,436 @@ namespace CS_3505_Project_06
             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 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 new game to start.\r
+        /// Reinitialize the private variables in preparation for new game to start.\r
         /// </summary>\r
         void Reset()\r
         {\r
             mLatency = 1;\r
             mNextLatencyAdjustmentFrame = 1;\r
             mStallCount = 0;\r
-            mAverageOwd = AverageOneWayDelay;\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
-            // TODO: The game object needs to be reset, too.\r
-            //mGame.ResetGame(playerIdentifiers, playerIdentifiers[0]);\r
+            mGame.ResetGame(GamerArray, LocalGamerInfo);\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
-        void ReadPackets()\r
+        void HandleIncomingPackets()\r
         {\r
-            foreach (LocalNetworkGamer gamer in mNetworkSession.LocalGamers)\r
+            LocalNetworkGamer localGamer = LocalGamer;\r
+\r
+            while (localGamer.IsDataAvailable)\r
             {\r
-                while (gamer.IsDataAvailable)\r
-                {\r
-                    NetworkGamer sender;\r
+                NetworkGamer sender;\r
 \r
-                    gamer.ReceiveData(mPacketReader, out sender);\r
-                    PacketType packetId = (PacketType)mPacketReader.ReadByte();\r
+                localGamer.ReceiveData(mPacketReader, out sender);\r
+                GamerInfo senderInfo = mGamers[sender.Id];\r
 \r
-                    switch (packetId)\r
-                    {\r
-                        case PacketType.Chat:\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
+                        short messageLength = mPacketReader.ReadInt16();\r
+                        char[] message = mPacketReader.ReadChars(messageLength);\r
 \r
-                            ChatPacket chatPacket = new ChatPacket(sender, new String(message));\r
-                            mChatPackets.Add(chatPacket);\r
-                            break;\r
+                        ChatInfo chatPacket = new ChatInfo(sender, new String(message));\r
+                        mChatPackets.Add(chatPacket);\r
+                        break;\r
+\r
+                    case PacketType.Event:\r
 \r
-                        case PacketType.Event:\r
+                        short stallCount = mPacketReader.ReadInt16();\r
+                        short averageOwd = mPacketReader.ReadInt16();\r
+                        int frameNumber = mPacketReader.ReadInt32();\r
+                        byte numEvents = mPacketReader.ReadByte();\r
 \r
-                            short stallCount = mPacketReader.ReadInt16();\r
-                            short averageOwd = mPacketReader.ReadInt16();\r
-                            int frameNumber = mPacketReader.ReadInt32();\r
-                            byte numEvents = mPacketReader.ReadByte();\r
+                        if (frameNumber <= senderInfo.HighestFrameNumber)\r
+                        {\r
+                            // we know about all these events, so don't bother reading them\r
+                            break;\r
+                        }\r
 \r
-                            for (byte i = 0; i < numEvents; ++i)\r
+                        for (byte i = 0; i < numEvents; ++i)\r
+                        {\r
+                            EventInfo eventInfo = ReadEvent(mPacketReader, sender);\r
+                            \r
+                            if (eventInfo != null && eventInfo.FrameOfApplication < senderInfo.HighestFrameNumber)\r
                             {\r
-                                ReadEvent(mPacketReader, sender);\r
+                                int index = EventArrayIndex;\r
+                                if (senderInfo.Events[index] == null) senderInfo.Events[index] = new List<EventInfo>();\r
+                                senderInfo.Events[index].Add(eventInfo);\r
                             }\r
+                        }\r
 \r
-                            break;\r
+                        senderInfo.StallCount = stallCount;\r
+                        senderInfo.AverageOwd = averageOwd;\r
+                        senderInfo.HighestFrameNumber = frameNumber;\r
+                        break;\r
 \r
-                        case PacketType.Stall:\r
+                    case PacketType.Stall:\r
 \r
-                            byte numStalledPeers = mPacketReader.ReadByte();\r
-                            byte[] stalledPeers = mPacketReader.ReadBytes(numStalledPeers);\r
+                        byte numStalledPeers = mPacketReader.ReadByte();\r
+                        byte[] stalledPeers = mPacketReader.ReadBytes(numStalledPeers);\r
 \r
-                            break;\r
-                    }\r
+                        // TODO\r
+\r
+                        break;\r
+\r
+                    default:\r
+\r
+                        Console.WriteLine("Received unknown packet type: " + (int)packetId);\r
+                        break;\r
                 }\r
             }\r
         }\r
 \r
-        void ReadEvent(PacketReader packetReader, NetworkGamer sender)\r
+\r
+        int EventArrayIndex\r
+        {\r
+            get { return (int)(mGame.CurrentFrameNumber % MaximumLatency); }\r
+        }\r
+\r
+        EventInfo ReadEvent(PacketReader packetReader, NetworkGamer sender)\r
         {\r
             EventType eventId = (EventType)packetReader.ReadByte();\r
-            long applicationFrame = packetReader.ReadInt32();\r
+            long frameNumber = packetReader.ReadInt32();\r
 \r
             switch (eventId)\r
             {\r
                 case EventType.KeyDown:\r
 \r
                     int keyCode1 = packetReader.ReadInt32();\r
-\r
-                    break;\r
+                    return new KeyboardEventInfo(sender, frameNumber, (Keys)keyCode1, true);\r
 \r
                 case EventType.KeyUp:\r
 \r
                     int keyCode2 = packetReader.ReadInt32();\r
-\r
-                    break;\r
+                    return new KeyboardEventInfo(sender, frameNumber, (Keys)keyCode2, false);\r
 \r
                 case EventType.MouseDown:\r
 \r
                     byte buttonId1 = packetReader.ReadByte();\r
-\r
-                    break;\r
+                    return new MouseButtonEventInfo(sender, frameNumber, (MouseButton)buttonId1, true);\r
 \r
                 case EventType.MouseUp:\r
 \r
                     byte buttonId2 = packetReader.ReadByte();\r
-\r
-                    break;\r
+                    return new MouseButtonEventInfo(sender, frameNumber, (MouseButton)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
-                    break;\r
+                default:\r
+\r
+                    Console.WriteLine("Received unknown event type: " + (int)eventId);\r
+                    return null;\r
             }\r
         }\r
 \r
-        void WriteChat(String message)\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)\r
+        {\r
+            mPacketWriter.Write((byte)PacketType.Event);\r
+            mPacketWriter.Write((short)mStallCount);\r
+            mPacketWriter.Write((short)mAverageOwd);\r
+            mPacketWriter.Write((int)(mGame.CurrentFrameNumber + mLatency));\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
-                // TODO\r
-                return false;\r
+                return mNextLatencyAdjustmentFrame == mGame.CurrentFrameNumber;\r
             }\r
         }\r
 \r
         void AdjustLatency()\r
         {\r
-            // TODO\r
+            Debug.Assert(IsLatencyAdjustmentFrame);\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
+\r
+            // DEBUG\r
+            int prevLatency = mLatency;\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
+            // DEBUG OUTPUT\r
+            if (prevLatency != mLatency) Console.WriteLine("Latency readjusted to " + mLatency);\r
+\r
+            if (mLatency < 1) mLatency = 1;\r
+            if (mLatency > MaximumLatency) mLatency = MaximumLatency;\r
+\r
+            mNextLatencyAdjustmentFrame = mGame.CurrentFrameNumber + mLatency;\r
+            mAverageOwd = CurrentAverageOneWayDelay;\r
+\r
+            mLastLocalEvents = mLocalEvents;\r
+            mLocalEvents = new List<EventInfo>();\r
         }\r
 \r
 \r
-        void SendLocalEvents()\r
+\r
+        List<EventInfo> GetEventsFromInput()\r
         {\r
-            // TODO: Not finished.\r
+            List<EventInfo> events = new List<EventInfo>();\r
 \r
-            KeyboardState keyState = Keyboard.GetState();\r
-            MouseState mouseState = Mouse.GetState();\r
+            // 1. Find the keyboard differences; written by Peter.\r
 \r
-            // Make a list of the keys pressed or released this frame.\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
-                if (!mLastPressedKeys.Contains(k))\r
-                    pressedKeys.Add(k);\r
-                else\r
-                    mLastPressedKeys.Remove(k);\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, mGame.CurrentFrameNumber, key, true));\r
+            }\r
+            foreach (Keys key in releasedKeys)\r
+            {\r
+                events.Add(new KeyboardEventInfo(LocalGamer, mGame.CurrentFrameNumber, key, false));\r
+            }\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, mGame.CurrentFrameNumber, MouseButton.Left, leftButtonPressed));\r
+            }\r
+\r
+            bool rightButtonPressed = mouseState.LeftButton == ButtonState.Pressed;\r
+            if (rightButtonPressed != mLastRightButtonPressed)\r
+            {\r
+                events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Right, rightButtonPressed));\r
+            }\r
+\r
+            bool middleButtonPressed = mouseState.LeftButton == ButtonState.Pressed;\r
+            if (middleButtonPressed != mLastMiddleButtonPressed)\r
+            {\r
+                events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, 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, mGame.CurrentFrameNumber, 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
-            bool buttonPressed = mouseState.LeftButton == ButtonState.Pressed;\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
+            List<EventInfo> events = new List<EventInfo>(mLocalEvents);\r
+            events.AddRange(mLastLocalEvents);\r
+\r
+            WriteEventPacket(events);\r
+\r
+            if (recipient != null)\r
+            {\r
+                LocalGamer.SendData(mPacketWriter, SendDataOptions.Reliable, recipient);\r
+            }\r
+            else\r
+            {\r
+                LocalGamer.SendData(mPacketWriter, SendDataOptions.None);\r
+            }\r
         }\r
 \r
 \r
@@ -521,23 +863,70 @@ namespace CS_3505_Project_06
         {\r
             get\r
             {\r
-                // TODO\r
+                long currentFrame = mGame.CurrentFrameNumber;\r
+\r
+                foreach (GamerInfo gamerInfo in mGamers.Values)\r
+                {\r
+                    if (gamerInfo.HighestFrameNumber < currentFrame) return false;\r
+                }\r
+\r
                 return true;\r
             }\r
         }\r
 \r
         void ApplyEvents()\r
         {\r
-            // TODO\r
+            int index = EventArrayIndex;\r
+\r
+            foreach (GamerInfo gamerInfo in GamerArray)\r
+            {\r
+                if (gamerInfo.Events[index] == null) continue;\r
+\r
+                foreach (EventInfo eventInfo in gamerInfo.Events[index])\r
+                {\r
+                    KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;\r
+                    if (keyboardEventInfo != null)\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
+                        mGame.ApplyMouseButtonInput(gamerInfo, mouseButtonEventInfo.IsButtonDown);\r
+                        continue;\r
+                    }\r
+\r
+                    MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;\r
+                    if (mouseMotionEventInfo != null)\r
+                    {\r
+                        mGame.ApplyMouseLocationInput(gamerInfo, mouseMotionEventInfo.X, mouseMotionEventInfo.Y);\r
+                        continue;\r
+                    }\r
+                }\r
+\r
+                gamerInfo.Events[index] = null;\r
+            }\r
         }\r
 \r
 \r
-        int AverageOneWayDelay\r
+        int CurrentAverageOneWayDelay\r
         {\r
             get\r
             {\r
-                // TODO\r
-                return 12;\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
This page took 0.046381 seconds and 4 git commands to generate.