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
/// </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
/// </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
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
}\r
else if (mNetworkSession.SessionState == NetworkSessionState.Playing)\r
{\r
- mLobby.Draw(spriteBatch);\r
+ mGame.Draw(spriteBatch);\r
}\r
}\r
}\r
/// 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
/// <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
/// <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
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
}\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
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 a 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
{\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