-using System;\r
+\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
public delegate void FoundSessionsDelegate(AvailableNetworkSessionCollection sessions, NetworkGame 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, NetworkGame 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
mJoinedSessionDelegate = callback;\r
NetworkSession.BeginCreate(NetworkSessionType.SystemLink, 1, maxGamers, CreateSessionEnd, null);\r
}\r
- private void CreateSessionEnd(IAsyncResult result)\r
+ void CreateSessionEnd(IAsyncResult result)\r
{\r
Debug.Assert(mNetworkSession == null);\r
\r
- mNetworkSession = NetworkSession.EndCreate(result);\r
- mNetworkSession.AllowHostMigration = true;\r
- mNetworkSession.AllowJoinInProgress = false;\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
mFoundSessionsDelegate = callback;\r
NetworkSession.BeginFind(NetworkSessionType.SystemLink, 1, null, new AsyncCallback(FindSessionsEnd), null);\r
}\r
- private void FindSessionsEnd(IAsyncResult result)\r
+ void FindSessionsEnd(IAsyncResult result)\r
{\r
- AvailableNetworkSessionCollection sessions = NetworkSession.EndFind(result);\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
mJoinedSessionDelegate = callback;\r
NetworkSession.BeginJoin(availableSession, JoinSessionEnd, null);\r
}\r
- private void JoinSessionEnd(IAsyncResult result)\r
+ void JoinSessionEnd(IAsyncResult result)\r
{\r
Debug.Assert(mNetworkSession == null);\r
\r
- mNetworkSession = NetworkSession.EndJoin(result);\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
mNetworkSession.StartGame();\r
mNetworkSession.ResetReady();\r
-\r
- Reset();\r
}\r
\r
\r
}\r
else if (mNetworkSession.SessionState == NetworkSessionState.Playing)\r
{\r
- //TODO reset needs to be called for all players, currently LocalGamerInfo throughs exception for all nonhosts\r
- // because in start game reset is only called on hosts games thus other clients never get an updated list\r
- // gamers.\r
-\r
-\r
-//thoughs exeption see TODO above\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
+ 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
- if (mStallCount % 60 == 0)\r
+ // Send a reliable event packet to each stalled gamer.\r
+ if (mStallCount == 1)\r
{\r
- Console.WriteLine("Stalled for " + mStallCount + " frames.");\r
- }\r
+#if DEBUG\r
+ Console.WriteLine("STAL: ====");\r
+#endif\r
\r
- /*if (mStallCount > StallTimeout)\r
- {\r
- DropLostGamers();\r
- mStallCount = 0;\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 == 1)\r
+ else if (mStallCount > 600)\r
{\r
- SendLocalEvents\r
+ Console.WriteLine("One or more players have stalled excessively. Leaving session...");\r
+ LeaveSession();\r
}\r
- else if (mStallCount % 60 == 0)\r
- {\r
- } TODO */\r
}\r
}\r
}\r
\r
\r
/// <summary>\r
- /// Get the chat messages that have been receive since the last time this\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
/// <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
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
enum PacketType\r
{\r
Chat = 1,\r
- Event = 2,\r
- Stall = 3\r
+ Event = 2\r
}\r
\r
enum EventType\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
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
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.Event:\r
\r
- short stallCount = mPacketReader.ReadInt16();\r
- short averageOwd = mPacketReader.ReadInt16();\r
+ GamerInfo senderInfo = mGamers[sender.Id];\r
+\r
+ int stallCount = mPacketReader.ReadInt16();\r
+ int averageOwd = mPacketReader.ReadInt16();\r
int frameNumber = mPacketReader.ReadInt32();\r
- byte numEvents = mPacketReader.ReadByte();\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
- for (byte i = 0; i < numEvents; ++i)\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
+ if (eventInfo != null && eventInfo.FrameOfApplication > senderInfo.HighestFrameNumber)\r
{\r
- int index = EventArrayIndex;\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.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
\r
Console.WriteLine("Received unknown packet type: " + (int)packetId);\r
}\r
\r
\r
- int EventArrayIndex\r
+ int CurrentEventArrayIndex\r
+ {\r
+ get { return GetEventArrayIndexForFrame(mGame.CurrentFrameNumber); }\r
+ }\r
+\r
+ int GetEventArrayIndexForFrame(long frame)\r
{\r
- get { return (int)(mGame.CurrentFrameNumber % MaximumLatency); }\r
+ return (int)(frame % MaximumLatency);\r
}\r
\r
EventInfo ReadEvent(PacketReader packetReader, NetworkGamer sender)\r
{\r
case EventType.KeyDown:\r
\r
- int keyCode1 = packetReader.ReadInt32();\r
- return new KeyboardEventInfo(sender, frameNumber, (Keys)keyCode1, true);\r
+ Keys keyCode1 = (Keys)packetReader.ReadInt32();\r
+ return new KeyboardEventInfo(sender, frameNumber, keyCode1, true);\r
\r
case EventType.KeyUp:\r
\r
- int keyCode2 = packetReader.ReadInt32();\r
- return new KeyboardEventInfo(sender, frameNumber, (Keys)keyCode2, false);\r
+ Keys keyCode2 = (Keys)packetReader.ReadInt32();\r
+ return new KeyboardEventInfo(sender, frameNumber, keyCode2, false);\r
\r
case EventType.MouseDown:\r
\r
- byte buttonId1 = packetReader.ReadByte();\r
- return new MouseButtonEventInfo(sender, frameNumber, (MouseButton)buttonId1, true);\r
+ MouseButton buttonId1 = (MouseButton)packetReader.ReadByte();\r
+ return new MouseButtonEventInfo(sender, frameNumber, buttonId1, true);\r
\r
case EventType.MouseUp:\r
\r
- byte buttonId2 = packetReader.ReadByte();\r
- return new MouseButtonEventInfo(sender, frameNumber, (MouseButton)buttonId2, false);\r
+ MouseButton buttonId2 = (MouseButton)packetReader.ReadByte();\r
+ return new MouseButtonEventInfo(sender, frameNumber, buttonId2, false);\r
\r
case EventType.MouseMove:\r
\r
mPacketWriter.Write(message.ToCharArray());\r
}\r
\r
- void WriteEventPacket(List<EventInfo> events)\r
+ void WriteEventPacket(List<EventInfo> events, long highestFrameNumber)\r
{\r
mPacketWriter.Write((byte)PacketType.Event);\r
- mPacketWriter.Write((short)mStallCount);\r
+ mPacketWriter.Write((short)mLastStallCount);\r
mPacketWriter.Write((short)mAverageOwd);\r
- mPacketWriter.Write((int)(mGame.CurrentFrameNumber + mLatency));\r
+ mPacketWriter.Write((int)highestFrameNumber);\r
mPacketWriter.Write((byte)events.Count);\r
\r
foreach (EventInfo eventInfo in events)\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
{\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
- // DEBUG\r
+#if DEBUG\r
int prevLatency = mLatency;\r
+#endif\r
\r
if (maxStallCount > 0)\r
{\r
}\r
else\r
{\r
- mLatency = (int)(0.6 * (double)(mLatency - maxAverageOwd) + 1.0);\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
+#if DEBUG\r
+ if (prevLatency != mLatency) Console.WriteLine("NLAG: " + mLatency);\r
+#endif\r
+\r
mNextLatencyAdjustmentFrame = mGame.CurrentFrameNumber + mLatency;\r
mAverageOwd = CurrentAverageOneWayDelay;\r
\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
foreach (Keys key in pressedKeys)\r
{\r
- events.Add(new KeyboardEventInfo(LocalGamer, mGame.CurrentFrameNumber, key, true));\r
+ events.Add(new KeyboardEventInfo(LocalGamer, frameOfApplication, key, true));\r
}\r
foreach (Keys key in releasedKeys)\r
{\r
- events.Add(new KeyboardEventInfo(LocalGamer, mGame.CurrentFrameNumber, key, false));\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
bool leftButtonPressed = mouseState.LeftButton == ButtonState.Pressed;\r
if (leftButtonPressed != mLastLeftButtonPressed)\r
{\r
- events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Left, leftButtonPressed));\r
+ events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Left, leftButtonPressed));\r
}\r
\r
- bool rightButtonPressed = mouseState.LeftButton == ButtonState.Pressed;\r
+ bool rightButtonPressed = mouseState.RightButton == ButtonState.Pressed;\r
if (rightButtonPressed != mLastRightButtonPressed)\r
{\r
- events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Right, rightButtonPressed));\r
+ events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Right, rightButtonPressed));\r
}\r
\r
- bool middleButtonPressed = mouseState.LeftButton == ButtonState.Pressed;\r
+ bool middleButtonPressed = mouseState.MiddleButton == ButtonState.Pressed;\r
if (middleButtonPressed != mLastMiddleButtonPressed)\r
{\r
- events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Middle, middleButtonPressed));\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, mGame.CurrentFrameNumber, mousePositionX, mousePositionY));\r
+ events.Add(new MouseMotionEventInfo(LocalGamer, frameOfApplication, mousePositionX, mousePositionY));\r
}\r
\r
// 3. Save the current peripheral state.\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
- WriteEventPacket(events);\r
-\r
- if (recipient != null)\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
foreach (GamerInfo gamerInfo in mGamers.Values)\r
{\r
+ if (mGame.IsGameOver(gamerInfo)) continue;\r
if (gamerInfo.HighestFrameNumber < currentFrame) return false;\r
}\r
\r
\r
void ApplyEvents()\r
{\r
- int index = EventArrayIndex;\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
- foreach (EventInfo eventInfo in gamerInfo.Events[index])\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
- KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;\r
- if (keyboardEventInfo != null)\r
- {\r
- mGame.ApplyKeyInput(gamerInfo, keyboardEventInfo.Key, keyboardEventInfo.IsKeyDown);\r
- continue;\r
- }\r
+#if DEBUG\r
+ Console.WriteLine(" KEY: " + keyboardEventInfo.FrameOfApplication + "\t" + keyboardEventInfo.Key + "," + keyboardEventInfo.IsKeyDown);\r
+#endif\r
\r
- MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;\r
- if (mouseButtonEventInfo != null)\r
- {\r
- mGame.ApplyMouseButtonInput(gamerInfo, mouseButtonEventInfo.IsButtonDown);\r
- continue;\r
- }\r
+ mGame.ApplyKeyInput(gamerInfo, keyboardEventInfo.Key, keyboardEventInfo.IsKeyDown);\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
+ 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
- gamerInfo.Events[index] = null;\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
averageOwd += timeSpan.TotalMilliseconds;\r
}\r
\r
- return (int)(averageOwd / numRemoteGamersTwice / 16.6666);\r
+ return (int)((averageOwd / numRemoteGamersTwice) / 16.6666);\r
}\r
}\r
\r