+ mGame.Draw(spriteBatch);\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Get the chat messages that have been receive 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
+ 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
+ ILobby 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 mNextLatencyAdjustmentFrame;\r
+ int mStallCount;\r
+ int mAverageOwd;\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
+ Stall = 3\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 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
+ mNextLatencyAdjustmentFrame = 1;\r
+ mStallCount = 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
+ GamerInfo senderInfo = mGamers[sender.Id];\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
+ short stallCount = mPacketReader.ReadInt16();\r
+ short averageOwd = mPacketReader.ReadInt16();\r
+ int frameNumber = mPacketReader.ReadInt32();\r
+ byte numEvents = mPacketReader.ReadByte();\r
+\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
+ {\r
+ EventInfo eventInfo = ReadEvent(mPacketReader, sender);\r
+ \r
+ if (eventInfo != null && eventInfo.FrameOfApplication < senderInfo.HighestFrameNumber)\r
+ {\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
+ senderInfo.StallCount = stallCount;\r
+ senderInfo.AverageOwd = averageOwd;\r
+ senderInfo.HighestFrameNumber = frameNumber;\r
+ break;\r
+\r
+ case PacketType.Stall:\r
+\r
+ byte numStalledPeers = mPacketReader.ReadByte();\r
+ byte[] stalledPeers = mPacketReader.ReadBytes(numStalledPeers);\r
+\r
+ // TODO\r
+\r
+ break;\r
+\r
+ default:\r