X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=Project06%2FCS%203505%20Project%2006%2FCS%203505%20Project%2006%2FNetworkGame.cs;h=ae0396bb1901fb85ff767b1e7e6752202c790e0c;hb=77f32a9cab6b5697359f7b6631943e8c583eac1a;hp=03b6e90481812e40680b720009379c554f43b089;hpb=89af32ed79f55de76dd9b88eeb214ede7e72639d;p=chaz%2Fcarfire
diff --git a/Project06/CS 3505 Project 06/CS 3505 Project 06/NetworkGame.cs b/Project06/CS 3505 Project 06/CS 3505 Project 06/NetworkGame.cs
index 03b6e90..ae0396b 100644
--- a/Project06/CS 3505 Project 06/CS 3505 Project 06/NetworkGame.cs
+++ b/Project06/CS 3505 Project 06/CS 3505 Project 06/NetworkGame.cs
@@ -1,4 +1,7 @@
-using System;
+
+//#define DEBUG
+
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -8,6 +11,7 @@ using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
+using System.Collections;
namespace CS_3505_Project_06
{
@@ -17,6 +21,9 @@ namespace CS_3505_Project_06
///
public class NetworkGame
{
+ // Public methods and properties
+ #region Public Methods
+
///
/// Called when a session has been created or joined using CreateSession() or JoinSession().
///
@@ -32,6 +39,21 @@ namespace CS_3505_Project_06
public delegate void FoundSessionsDelegate(AvailableNetworkSessionCollection sessions, NetworkGame networkGame);
+ ///
+ /// Called when an exception is thrown during an asynchronous operation.
+ ///
+ /// The exception that was thrown.
+ /// The NetworkGame that errored.
+ public delegate void CaughtErrorDelegate(Exception exception, NetworkGame networkGame);
+
+ ///
+ /// Get and set the error delegate, called when an exception is thrown during
+ /// and asynchronous operation. This will occur if you try to create or join a
+ /// session without being logged into a profile.
+ ///
+ public CaughtErrorDelegate ErrorDelegate;
+
+
///
/// Construct a NetworkGame with a lobby and a game.
///
@@ -93,15 +115,28 @@ namespace CS_3505_Project_06
mJoinedSessionDelegate = callback;
NetworkSession.BeginCreate(NetworkSessionType.SystemLink, 1, maxGamers, CreateSessionEnd, null);
}
- private void CreateSessionEnd(IAsyncResult result)
+ void CreateSessionEnd(IAsyncResult result)
{
Debug.Assert(mNetworkSession == null);
- mNetworkSession = NetworkSession.EndCreate(result);
- mNetworkSession.AllowHostMigration = true;
- mNetworkSession.AllowJoinInProgress = false;
-
+ try
+ {
+ mNetworkSession = NetworkSession.EndCreate(result);
+ mNetworkSession.AllowHostMigration = true;
+ mNetworkSession.AllowJoinInProgress = false;
+ mNetworkSession.GameStarted += new EventHandler(GameStartedEvent);
+ }
+ catch (Exception e)
+ {
+ if (ErrorDelegate != null) ErrorDelegate(e, this);
+ return;
+ }
mJoinedSessionDelegate(mNetworkSession, this);
+ mJoinedSessionDelegate = null;
+ }
+ void GameStartedEvent(object sender, GameStartedEventArgs e)
+ {
+ Reset();
}
///
@@ -129,10 +164,20 @@ namespace CS_3505_Project_06
mFoundSessionsDelegate = callback;
NetworkSession.BeginFind(NetworkSessionType.SystemLink, 1, null, new AsyncCallback(FindSessionsEnd), null);
}
- private void FindSessionsEnd(IAsyncResult result)
+ void FindSessionsEnd(IAsyncResult result)
{
- AvailableNetworkSessionCollection sessions = NetworkSession.EndFind(result);
+ AvailableNetworkSessionCollection sessions;
+ try
+ {
+ sessions = NetworkSession.EndFind(result);
+ }
+ catch (Exception e)
+ {
+ if (ErrorDelegate != null) ErrorDelegate(e, this);
+ return;
+ }
mFoundSessionsDelegate(sessions, this);
+ mFoundSessionsDelegate = null;
}
///
@@ -148,12 +193,20 @@ namespace CS_3505_Project_06
mJoinedSessionDelegate = callback;
NetworkSession.BeginJoin(availableSession, JoinSessionEnd, null);
}
- private void JoinSessionEnd(IAsyncResult result)
+ void JoinSessionEnd(IAsyncResult result)
{
Debug.Assert(mNetworkSession == null);
- mNetworkSession = NetworkSession.EndJoin(result);
-
+ try
+ {
+ mNetworkSession = NetworkSession.EndJoin(result);
+ mNetworkSession.GameStarted += new EventHandler(GameStartedEvent);
+ }
+ catch (Exception e)
+ {
+ if (ErrorDelegate != null) ErrorDelegate(e, this);
+ return;
+ }
mJoinedSessionDelegate(mNetworkSession, this);
mJoinedSessionDelegate = null;
}
@@ -190,8 +243,19 @@ namespace CS_3505_Project_06
///
public void StartGame()
{
- Debug.Assert(mNetworkSession != null && mNetworkSession.IsHost);
+ Debug.Assert(mNetworkSession != null && mNetworkSession.IsHost &&
+ mNetworkSession.AllGamers.Count >= mGame.MinimumSupportedPlayers &&
+ mNetworkSession.IsEveryoneReady);
+
+ ForceStartGame();
+ }
+ ///
+ /// Indicate that the game should begin. This is like StartGame() without the sanity
+ /// checks. Use this for debugging.
+ ///
+ public void ForceStartGame()
+ {
mNetworkSession.StartGame();
mNetworkSession.ResetReady();
}
@@ -210,34 +274,79 @@ namespace CS_3505_Project_06
else
{
mNetworkSession.Update();
- ReadPackets();
+ HandleIncomingPackets();
if (mNetworkSession.SessionState == NetworkSessionState.Lobby)
{
- if (mNetworkSession.IsHost &&
- mNetworkSession.AllGamers.Count >= mGame.MinimumSupportedPlayers &&
- mNetworkSession.IsEveryoneReady)
- {
- mNetworkSession.StartGame();
- mNetworkSession.ResetReady();
- }
- else
- {
- mLobby.Update(gameTime, this);
- }
+ mLobby.Update(gameTime, this);
}
else if (mNetworkSession.SessionState == NetworkSessionState.Playing)
{
+ if (mGame.IsGameOver(LocalGamerInfo) || mGame.IsTerminated(LocalGamerInfo))
+ {
+ // TODO: Should support moving back to the session lobby.
+ LeaveSession();
+ return;
+ }
+
if (HaveNeededEvents)
{
- if (IsLatencyAdjustmentFrame) AdjustLatency();
- mStallCount = 0;
+ if (IsLatencyAdjustmentFrame)
+ {
+ AdjustLatency();
+ mLastStallCount = mStallCount;
+ mStallCount = 0;
+ }
+ mLocalEvents.AddRange(GetEventsFromInput());
SendLocalEvents();
ApplyEvents();
+
+#if DEBUG
+ Console.WriteLine("HASH: " + mGame.CurrentFrameNumber + "\t" + mGame.CurrentChecksum);
+#endif
+
mGame.Update(mTargetTimeSpan);
}
else // Stall!
{
+ if (mStallCount == 0)
+ {
+#if DEBUG
+ Console.WriteLine("STAL: ====");
+#endif
+ }
+ else if (mStallCount % 60 == 0)
+ {
+ // DEBUG
+ //Console.WriteLine("Stalled for " + mStallCount + " frames.");
+ }
+
+ mStallCount++;
+
+ // Send a reliable event packet to each stalled gamer.
+ if (mStallCount == 1)
+ {
+ foreach (GamerInfo gamerInfo in GamerArray)
+ {
+ if (gamerInfo.HighestFrameNumber < mGame.CurrentFrameNumber)
+ {
+ SendLocalEvents(gamerInfo.Gamer);
+ }
+ }
+ }
+
+ /*if (mStallCount > StallTimeout)
+ {
+ DropLostGamers();
+ mStallCount = 0;
+ }
+ else if (mStallCount == 1)
+ {
+ SendLocalEvents
+ }
+ else if (mStallCount % 60 == 0)
+ {
+ } TODO */
}
}
}
@@ -263,21 +372,21 @@ namespace CS_3505_Project_06
}
else if (mNetworkSession.SessionState == NetworkSessionState.Playing)
{
- mLobby.Draw(spriteBatch);
+ mGame.Draw(spriteBatch);
}
}
}
///
- /// Get the chat messages that have been receive since the last time this
+ /// Get the chat messages that have been received since the last time this
/// method was called.
///
/// List container of the chat messages.
- public List ReceiveChats()
+ public List ReceiveChats()
{
- List chats = mChatPackets;
- mChatPackets = new List();
+ List chats = mChatPackets;
+ mChatPackets = new List();
return chats;
}
@@ -288,7 +397,7 @@ namespace CS_3505_Project_06
/// The text of the message.
public void SendChat(String message)
{
- WriteChat(message);
+ WriteChatPacket(message);
LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder);
}
@@ -300,10 +409,14 @@ namespace CS_3505_Project_06
/// The gamer to receive the message.
public void SendChat(String message, NetworkGamer recipient)
{
- WriteChat(message);
+ Debug.Assert(recipient != null && !recipient.IsDisposed);
+
+ WriteChatPacket(message);
LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder, recipient);
}
+ #endregion
+
// Private class variable members
#region Instance Variables
@@ -318,16 +431,29 @@ namespace CS_3505_Project_06
ILobby mLobby;
IDeterministicGame mGame;
- List mChatPackets = new List();
+ List mChatPackets = new List();
+
+ List mLocalEvents = new List();
+ List mLastLocalEvents = new List();
List mLastPressedKeys = new List();
- bool mLastButtonPressed;
+ bool mLastLeftButtonPressed;
+ bool mLastRightButtonPressed;
+ bool mLastMiddleButtonPressed;
+ int mLastMousePositionX;
+ int mLastMousePositionY;
int mLatency;
+ long mHighestFrameNumber;
long mNextLatencyAdjustmentFrame;
int mStallCount;
+ int mLastStallCount;
int mAverageOwd;
+#if DEBUG
+ bool mDontSendEvents;
+#endif
+
TimeSpan mTargetTimeSpan = new TimeSpan(166666);
public TimeSpan TargetTimeSpan
{
@@ -337,11 +463,32 @@ namespace CS_3505_Project_06
}
}
+ Dictionary mGamers;
+ GamerInfo[] GamerArray
+ {
+ get
+ {
+ GamerInfo[] gamerList = mGamers.Values.ToArray();
+ Array.Sort(gamerList, delegate(GamerInfo a, GamerInfo b)
+ {
+ return a.Gamer.Id.CompareTo(b.Gamer.Id);
+ });
+ return gamerList;
+ }
+ }
+ GamerInfo LocalGamerInfo
+ {
+ get
+ {
+ return mGamers[LocalGamer.Id];
+ }
+ }
+
#endregion
- // Private implementation methods of the network protocol
- #region Private Implementation Methods
+ // Private types for the implementation of the network protocol
+ #region Private Types
enum PacketType
{
@@ -359,161 +506,490 @@ namespace CS_3505_Project_06
MouseMove = 5
}
+ enum MouseButton
+ {
+ Left = 1,
+ Right = 2,
+ Middle = 3
+ }
+
+ abstract class EventInfo
+ {
+ public NetworkGamer Gamer;
+ public long FrameOfApplication;
+
+ public EventInfo(NetworkGamer gamer, long frameNumber)
+ {
+ Gamer = gamer;
+ FrameOfApplication = frameNumber;
+ }
+
+ public abstract EventType Id
+ {
+ get;
+ }
+ }
+
+ class KeyboardEventInfo : EventInfo
+ {
+ public Keys Key;
+ public bool IsKeyDown;
+
+ public KeyboardEventInfo(NetworkGamer gamer, long frameNumber, Keys key, bool isDown)
+ : base(gamer, frameNumber)
+ {
+ Key = key;
+ IsKeyDown = isDown;
+ }
+
+ public override EventType Id
+ {
+ get { return IsKeyDown ? EventType.KeyDown : EventType.KeyUp; }
+ }
+ }
+
+ class MouseButtonEventInfo : EventInfo
+ {
+ public MouseButton Button;
+ public bool IsButtonDown;
+
+ public MouseButtonEventInfo(NetworkGamer gamer, long frameNumber, MouseButton button, bool isDown)
+ : base(gamer, frameNumber)
+ {
+ Button = button;
+ IsButtonDown = isDown;
+ }
+
+ public override EventType Id
+ {
+ get { return IsButtonDown ? EventType.MouseDown : EventType.MouseUp; }
+ }
+ }
+
+ class MouseMotionEventInfo : EventInfo
+ {
+ public int X;
+ public int Y;
+
+ public MouseMotionEventInfo(NetworkGamer gamer, long frameNumber, int x, int y)
+ : base(gamer, frameNumber)
+ {
+ X = x;
+ Y = y;
+ }
+
+ public override EventType Id
+ {
+ get { return EventType.MouseMove; }
+ }
+ }
+
+ class GamerInfo
+ {
+ public NetworkGamer Gamer;
+ public long HighestFrameNumber = 0;
+ public int StallCount = 0;
+ public int AverageOwd = 0;
+ public int NextStallCount = 0;
+ public int NextAverageOwd = 0;
+ public bool IsWaitedOn = false;
+ public List[] Events = new List[MaximumLatency];
+
+ public GamerInfo(NetworkGamer gamer)
+ {
+ Gamer = gamer;
+ }
+ }
+
+ const int MaximumLatency = 120;
+ const int StallTimeout = 900;
+
+ #endregion
+
+
+ // Private implementation methods of the network protocol
+ #region Private Implementation Methods
///
- /// Reinitialize the private variables in preparation for new game to start.
+ /// Reinitialize the private variables in preparation for a new game to start.
///
void Reset()
{
mLatency = 1;
+ mHighestFrameNumber = 0;
mNextLatencyAdjustmentFrame = 1;
mStallCount = 0;
- mAverageOwd = AverageOneWayDelay;
+ mLastStallCount = 0;
+ mAverageOwd = CurrentAverageOneWayDelay;
+
+ mGamers = new Dictionary();
+ foreach (NetworkGamer gamer in NetworkGamers)
+ {
+ mGamers.Add(gamer.Id, new GamerInfo(gamer));
+ }
- // TODO: The game object needs to be reset, too.
- //mGame.ResetGame(playerIdentifiers, playerIdentifiers[0]);
+ mGame.ResetGame(GamerArray, LocalGamerInfo);
}
- ///
- /// Allows either the lobby or the game to draw, depending on the state
- /// of the network connection and whether or not a game is in progress.
- ///
- /// Pass the time away.
- /// The sprite batch.
- void ReadPackets()
+ void HandleIncomingPackets()
{
- foreach (LocalNetworkGamer gamer in mNetworkSession.LocalGamers)
- {
- while (gamer.IsDataAvailable)
- {
- NetworkGamer sender;
+ LocalNetworkGamer localGamer = LocalGamer;
- gamer.ReceiveData(mPacketReader, out sender);
- PacketType packetId = (PacketType)mPacketReader.ReadByte();
-
- switch (packetId)
- {
- case PacketType.Chat:
+ while (localGamer.IsDataAvailable)
+ {
+ NetworkGamer sender;
- short messageLength = mPacketReader.ReadInt16();
- char[] message = mPacketReader.ReadChars(messageLength);
+ localGamer.ReceiveData(mPacketReader, out sender);
- ChatPacket chatPacket = new ChatPacket(sender, new String(message));
- mChatPackets.Add(chatPacket);
+ PacketType packetId = (PacketType)mPacketReader.ReadByte();
+ switch (packetId)
+ {
+ case PacketType.Chat:
+
+ short messageLength = mPacketReader.ReadInt16();
+ char[] message = mPacketReader.ReadChars(messageLength);
+
+ ChatInfo chatPacket = new ChatInfo(sender, new String(message));
+ mChatPackets.Add(chatPacket);
+ break;
+
+ case PacketType.Event:
+
+ GamerInfo senderInfo = mGamers[sender.Id];
+
+ int stallCount = mPacketReader.ReadInt16();
+ int averageOwd = mPacketReader.ReadInt16();
+ int frameNumber = mPacketReader.ReadInt32();
+ int numEvents = mPacketReader.ReadByte();
+
+ if (frameNumber <= mNextLatencyAdjustmentFrame)
+ {
+ senderInfo.StallCount = stallCount;
+ senderInfo.AverageOwd = averageOwd;
+ }
+ else
+ {
+ senderInfo.NextStallCount = stallCount;
+ senderInfo.NextAverageOwd = averageOwd;
+ }
+
+ if (frameNumber <= senderInfo.HighestFrameNumber)
+ {
+#if DEBUG
+ Console.WriteLine("SKP" + (char)sender.Id + ": " + mGame.CurrentFrameNumber + "\t" + frameNumber + "\t<=\t" + senderInfo.HighestFrameNumber + "\t#" + numEvents);
+#endif
+
+ // we know about all these events, so don't bother reading them
break;
+ }
- case PacketType.Event:
+#if DEBUG
+ Console.WriteLine(" GOT" + (char)sender.Id + ": " + mGame.CurrentFrameNumber + "\t" + frameNumber + "\t>\t" + senderInfo.HighestFrameNumber + "\t#" + numEvents);
+#endif
- short stallCount = mPacketReader.ReadInt16();
- short averageOwd = mPacketReader.ReadInt16();
- int frameNumber = mPacketReader.ReadInt32();
- byte numEvents = mPacketReader.ReadByte();
-
- for (byte i = 0; i < numEvents; ++i)
+ for (int i = 0; i < numEvents; i++)
+ {
+ EventInfo eventInfo = ReadEvent(mPacketReader, sender);
+
+ if (eventInfo != null && eventInfo.FrameOfApplication > senderInfo.HighestFrameNumber)
{
- ReadEvent(mPacketReader, sender);
+ int index = GetEventArrayIndexForFrame(eventInfo.FrameOfApplication);
+ if (senderInfo.Events[index] == null) senderInfo.Events[index] = new List();
+ senderInfo.Events[index].Add(eventInfo);
}
+ }
- break;
+ senderInfo.HighestFrameNumber = frameNumber;
+ break;
- case PacketType.Stall:
+ case PacketType.Stall:
- byte numStalledPeers = mPacketReader.ReadByte();
- byte[] stalledPeers = mPacketReader.ReadBytes(numStalledPeers);
+ GamerInfo senderInfo2 = mGamers[sender.Id];
- break;
- }
+ byte numStalledPeers = mPacketReader.ReadByte();
+ byte[] stalledPeers = mPacketReader.ReadBytes(numStalledPeers);
+
+ // TODO
+ break;
+
+ default:
+
+ Console.WriteLine("Received unknown packet type: " + (int)packetId);
+ break;
}
}
}
- void ReadEvent(PacketReader packetReader, NetworkGamer sender)
+
+ int CurrentEventArrayIndex
+ {
+ get { return GetEventArrayIndexForFrame(mGame.CurrentFrameNumber); }
+ }
+
+ int GetEventArrayIndexForFrame(long frame)
+ {
+ return (int)(frame % MaximumLatency);
+ }
+
+ EventInfo ReadEvent(PacketReader packetReader, NetworkGamer sender)
{
EventType eventId = (EventType)packetReader.ReadByte();
- long applicationFrame = packetReader.ReadInt32();
+ long frameNumber = packetReader.ReadInt32();
switch (eventId)
{
case EventType.KeyDown:
- int keyCode1 = packetReader.ReadInt32();
-
- break;
+ Keys keyCode1 = (Keys)packetReader.ReadInt32();
+ return new KeyboardEventInfo(sender, frameNumber, keyCode1, true);
case EventType.KeyUp:
- int keyCode2 = packetReader.ReadInt32();
-
- break;
+ Keys keyCode2 = (Keys)packetReader.ReadInt32();
+ return new KeyboardEventInfo(sender, frameNumber, keyCode2, false);
case EventType.MouseDown:
- byte buttonId1 = packetReader.ReadByte();
-
- break;
+ MouseButton buttonId1 = (MouseButton)packetReader.ReadByte();
+ return new MouseButtonEventInfo(sender, frameNumber, buttonId1, true);
case EventType.MouseUp:
- byte buttonId2 = packetReader.ReadByte();
-
- break;
+ MouseButton buttonId2 = (MouseButton)packetReader.ReadByte();
+ return new MouseButtonEventInfo(sender, frameNumber, buttonId2, false);
case EventType.MouseMove:
short x = packetReader.ReadInt16();
short y = packetReader.ReadInt16();
+ return new MouseMotionEventInfo(sender, frameNumber, x, y);
+
+ default:
- break;
+ Console.WriteLine("Received unknown event type: " + (int)eventId);
+ return null;
}
}
- void WriteChat(String message)
+
+ void WriteChatPacket(String message)
{
mPacketWriter.Write((byte)PacketType.Chat);
mPacketWriter.Write((short)message.Length);
mPacketWriter.Write(message.ToCharArray());
}
+ void WriteEventPacket(List events, long highestFrameNumber)
+ {
+ mPacketWriter.Write((byte)PacketType.Event);
+ mPacketWriter.Write((short)mLastStallCount);
+ mPacketWriter.Write((short)mAverageOwd);
+ mPacketWriter.Write((int)highestFrameNumber);
+ mPacketWriter.Write((byte)events.Count);
+
+ foreach (EventInfo eventInfo in events)
+ {
+ mPacketWriter.Write((byte)eventInfo.Id);
+ mPacketWriter.Write((int)eventInfo.FrameOfApplication);
+
+ KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;
+ if (keyboardEventInfo != null)
+ {
+ mPacketWriter.Write((int)keyboardEventInfo.Key);
+ continue;
+ }
+
+ MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;
+ if (mouseButtonEventInfo != null)
+ {
+ mPacketWriter.Write((byte)mouseButtonEventInfo.Button);
+ continue;
+ }
+
+ MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;
+ if (mouseMotionEventInfo != null)
+ {
+ mPacketWriter.Write((short)mouseMotionEventInfo.X);
+ mPacketWriter.Write((short)mouseMotionEventInfo.Y);
+ continue;
+ }
+ }
+ }
+
bool IsLatencyAdjustmentFrame
{
get
{
- // TODO
- return false;
+ return mNextLatencyAdjustmentFrame == mGame.CurrentFrameNumber;
}
}
void AdjustLatency()
{
- // TODO
+ Debug.Assert(IsLatencyAdjustmentFrame);
+
+#if DEBUG
+ if (mStallCount > 0)
+ {
+ Console.WriteLine("STL#: " + mGame.CurrentFrameNumber + "\t" + mStallCount);
+ }
+#endif
+
+ int maxStallCount = 0;
+ int maxAverageOwd = 0;
+
+ foreach (GamerInfo gamerInfo in GamerArray)
+ {
+ if (gamerInfo.StallCount > maxStallCount) maxStallCount = gamerInfo.StallCount;
+ if (gamerInfo.AverageOwd > maxAverageOwd) maxAverageOwd = gamerInfo.AverageOwd;
+
+ gamerInfo.StallCount = gamerInfo.NextStallCount;
+ gamerInfo.AverageOwd = gamerInfo.NextAverageOwd;
+ }
+
+#if DEBUG
+ int prevLatency = mLatency;
+#endif
+
+ if (maxStallCount > 0)
+ {
+ mLatency += maxStallCount;
+ }
+ else
+ {
+ mLatency -= (int)(0.6 * (double)(mLatency - maxAverageOwd) + 1.0);
+ }
+
+ if (mLatency < 1) mLatency = 1;
+ if (mLatency > MaximumLatency) mLatency = MaximumLatency;
+
+#if DEBUG
+ if (prevLatency != mLatency) Console.WriteLine("NLAG: " + mLatency);
+#endif
+
+ mNextLatencyAdjustmentFrame = mGame.CurrentFrameNumber + mLatency;
+ mAverageOwd = CurrentAverageOneWayDelay;
+
+ mLastLocalEvents = mLocalEvents;
+ mLocalEvents = new List();
}
- void SendLocalEvents()
+
+ List GetEventsFromInput()
{
- // TODO: Not finished.
+ List events = new List();
- KeyboardState keyState = Keyboard.GetState();
- MouseState mouseState = Mouse.GetState();
+ long frameOfApplication = mGame.CurrentFrameNumber + mLatency;
+ if (frameOfApplication <= mHighestFrameNumber) return events;
+ else mHighestFrameNumber = frameOfApplication;
+
+ // 1. Find the keyboard differences; written by Peter.
- // Make a list of the keys pressed or released this frame.
+ KeyboardState keyState = Keyboard.GetState();
List pressedKeys = new List();
List releasedKeys = new List();
Keys[] pressedKeysArray = keyState.GetPressedKeys();
foreach (Keys k in pressedKeysArray)
- if (!mLastPressedKeys.Contains(k))
- pressedKeys.Add(k);
- else
- mLastPressedKeys.Remove(k);
+ {
+ if (!mLastPressedKeys.Contains(k)) pressedKeys.Add(k);
+ else mLastPressedKeys.Remove(k);
+ }
releasedKeys = mLastPressedKeys;
+
+ foreach (Keys key in pressedKeys)
+ {
+ events.Add(new KeyboardEventInfo(LocalGamer, frameOfApplication, key, true));
+ }
+ foreach (Keys key in releasedKeys)
+ {
+ events.Add(new KeyboardEventInfo(LocalGamer, frameOfApplication, key, false));
+ }
+
+#if DEBUG
+ if (pressedKeys.Contains(Keys.Escape)) mDontSendEvents = true;
+ if (releasedKeys.Contains(Keys.Escape)) mDontSendEvents = false;
+#endif
+
+ // 2. Find the mouse differences.
+
+ MouseState mouseState = Mouse.GetState();
+
+ bool leftButtonPressed = mouseState.LeftButton == ButtonState.Pressed;
+ if (leftButtonPressed != mLastLeftButtonPressed)
+ {
+ events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Left, leftButtonPressed));
+ }
+
+ bool rightButtonPressed = mouseState.RightButton == ButtonState.Pressed;
+ if (rightButtonPressed != mLastRightButtonPressed)
+ {
+ events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Right, rightButtonPressed));
+ }
+
+ bool middleButtonPressed = mouseState.MiddleButton == ButtonState.Pressed;
+ if (middleButtonPressed != mLastMiddleButtonPressed)
+ {
+ events.Add(new MouseButtonEventInfo(LocalGamer, frameOfApplication, MouseButton.Middle, middleButtonPressed));
+ }
+
+ int mousePositionX = mouseState.X;
+ int mousePositionY = mouseState.Y;
+ if (mousePositionX != mLastMousePositionX || mousePositionY != mLastMousePositionY)
+ {
+ events.Add(new MouseMotionEventInfo(LocalGamer, frameOfApplication, mousePositionX, mousePositionY));
+ }
+
+ // 3. Save the current peripheral state.
+
mLastPressedKeys = new List(pressedKeysArray);
+ mLastLeftButtonPressed = leftButtonPressed;
+ mLastRightButtonPressed = rightButtonPressed;
+ mLastMiddleButtonPressed = middleButtonPressed;
+ mLastMousePositionX = mousePositionX;
+ mLastMousePositionY = mousePositionY;
+
+ return events;
+ }
+
+ void SendLocalEvents()
+ {
+ SendLocalEvents((NetworkGamer)null);
+ }
+
+ void SendLocalEvents(List recipicents)
+ {
+ foreach (NetworkGamer gamer in recipicents)
+ {
+ SendLocalEvents(gamer);
+ }
+ }
+
+ void SendLocalEvents(NetworkGamer recipient)
+ {
+#if DEBUG
+ if (mDontSendEvents) return;
+#endif
+
+ List events = new List(mLocalEvents);
+ events.AddRange(mLastLocalEvents);
- bool buttonPressed = mouseState.LeftButton == ButtonState.Pressed;
+ if (recipient != null && !recipient.IsDisposed)
+ {
+ // if there is a recipient, we are resending old events
+ WriteEventPacket(events, mGame.CurrentFrameNumber - 1);
+ LocalGamer.SendData(mPacketWriter, SendDataOptions.Reliable, recipient);
+ }
+ else
+ {
+ WriteEventPacket(events, mGame.CurrentFrameNumber + mLatency);
+ LocalGamer.SendData(mPacketWriter, SendDataOptions.None);
+ }
}
@@ -521,23 +997,82 @@ namespace CS_3505_Project_06
{
get
{
- // TODO
+ long currentFrame = mGame.CurrentFrameNumber;
+
+ foreach (GamerInfo gamerInfo in mGamers.Values)
+ {
+ if (gamerInfo.HighestFrameNumber < currentFrame) return false;
+ }
+
return true;
}
}
void ApplyEvents()
{
- // TODO
+ int index = CurrentEventArrayIndex;
+
+ foreach (GamerInfo gamerInfo in GamerArray)
+ {
+ if (gamerInfo.Events[index] == null) continue;
+
+ foreach (EventInfo eventInfo in gamerInfo.Events[index])
+ {
+ KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;
+ if (keyboardEventInfo != null)
+ {
+#if DEBUG
+ Console.WriteLine(" KEY: " + keyboardEventInfo.FrameOfApplication + "\t" + keyboardEventInfo.Key + "," + keyboardEventInfo.IsKeyDown);
+#endif
+
+ mGame.ApplyKeyInput(gamerInfo, keyboardEventInfo.Key, keyboardEventInfo.IsKeyDown);
+ continue;
+ }
+
+ MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;
+ if (mouseButtonEventInfo != null)
+ {
+#if DEBUG
+ Console.WriteLine(" BTN: " + mouseButtonEventInfo.FrameOfApplication + "\t" + mouseButtonEventInfo.IsButtonDown);
+#endif
+
+ mGame.ApplyMouseButtonInput(gamerInfo, mouseButtonEventInfo.IsButtonDown);
+ continue;
+ }
+
+ MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;
+ if (mouseMotionEventInfo != null)
+ {
+#if DEBUG
+ Console.WriteLine(" MMV: " + mouseMotionEventInfo.FrameOfApplication + "\t" + mouseMotionEventInfo.X + "," + mouseMotionEventInfo.Y);
+#endif
+
+ mGame.ApplyMouseLocationInput(gamerInfo, mouseMotionEventInfo.X, mouseMotionEventInfo.Y);
+ continue;
+ }
+ }
+
+ gamerInfo.Events[index] = null;
+ }
}
- int AverageOneWayDelay
+ int CurrentAverageOneWayDelay
{
get
{
- // TODO
- return 12;
+ Debug.Assert(mNetworkSession != null);
+
+ double numRemoteGamersTwice = 2 * mNetworkSession.RemoteGamers.Count;
+ double averageOwd = 0;
+
+ foreach (NetworkGamer gamer in mNetworkSession.RemoteGamers)
+ {
+ TimeSpan timeSpan = gamer.RoundtripTime;
+ averageOwd += timeSpan.TotalMilliseconds;
+ }
+
+ return (int)((averageOwd / numRemoteGamersTwice) / 16.6666);
}
}