]> Dogcows Code - chaz/carfire/blob - Project06/CS 3505 Project 06/CS 3505 Project 06/NetworkGame.cs
New delegate method for getting and handling errors during the async calls. Need...
[chaz/carfire] / Project06 / CS 3505 Project 06 / CS 3505 Project 06 / NetworkGame.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Microsoft.Xna.Framework.Net;
6 using System.Diagnostics;
7 using Microsoft.Xna.Framework.GamerServices;
8 using Microsoft.Xna.Framework.Graphics;
9 using Microsoft.Xna.Framework;
10 using Microsoft.Xna.Framework.Input;
11 using System.Collections;
12
13 namespace CS_3505_Project_06
14 {
15 /// <summary>
16 /// A manager class to handle network interactions between peers and
17 /// lobby/game switching.
18 /// </summary>
19 public class NetworkGame
20 {
21 // Public methods and properties
22 #region Public Methods
23
24 /// <summary>
25 /// Called when a session has been created or joined using CreateSession() or JoinSession().
26 /// </summary>
27 /// <param name="session">The new session that was created or joined.</param>
28 /// <param name="networkGame">The NetworkGame that joined the session.</param>
29 public delegate void JoinedSessionDelegate(NetworkSession session, NetworkGame networkGame);
30
31 /// <summary>
32 /// Called when sessions are found as a result of calling FindSessions().
33 /// </summary>
34 /// <param name="sessions">A container of the available sessions.</param>
35 /// <param name="networkGame">The NetworkGame that searched for the sessions.</param>
36 public delegate void FoundSessionsDelegate(AvailableNetworkSessionCollection sessions, NetworkGame networkGame);
37
38
39 /// <summary>
40 /// Called when an exception is thrown during an asynchronous operation.
41 /// </summary>
42 /// <param name="exception">The exception that was thrown.</param>
43 /// <param name="networkGame">The NetworkGame that errored.</param>
44 public delegate void CaughtErrorDelegate(Exception exception, NetworkGame networkGame);
45
46 /// <summary>
47 /// Get and set the error delegate, called when an exception is thrown during
48 /// and asynchronous operation. This will occur if you try to create or join a
49 /// session without being logged into a profile.
50 /// </summary>
51 public CaughtErrorDelegate ErrorDelegate;
52
53
54 /// <summary>
55 /// Construct a NetworkGame with a lobby and a game.
56 /// </summary>
57 /// <param name="lobby">Provides an associated lobby to update and draw.</param>
58 /// <param name="game">Provides a game object to be played over the network.</param>
59 public NetworkGame(ILobby lobby, IDeterministicGame game)
60 {
61 Debug.Assert(lobby != null && game != null);
62
63 mLobby = lobby;
64 mGame = game;
65 }
66
67
68 /// <summary>
69 /// Get the Gamer object for the local player.
70 /// </summary>
71 public LocalNetworkGamer LocalGamer
72 {
73 get
74 {
75 // TODO: Is this the correct way to get the single local gamer?
76 return mNetworkSession.LocalGamers[0];
77 }
78 }
79
80 /// <summary>
81 /// Get all the gamers associated with the active network session.
82 /// </summary>
83 public GamerCollection<NetworkGamer> NetworkGamers
84 {
85 get
86 {
87 return mNetworkSession.AllGamers;
88 }
89 }
90
91
92 /// <summary>
93 /// Begin a new network session with the local gamer as the host. You must not
94 /// call this method or use JoinSession without first using LeaveSession.
95 /// </summary>
96 /// <param name="callback">The delegate/method to call when the session is created.</param>
97 public void CreateSession(JoinedSessionDelegate callback)
98 {
99 CreateSession(mGame.MaximumSupportedPlayers, callback);
100 }
101
102 /// <summary>
103 /// Begin a new network session with the local gamer as the host. You must not
104 /// call this method or use JoinSession without first using LeaveSession.
105 /// </summary>
106 /// <param name="maxGamers">Provide the maximum number of players allowed to connect.</param>
107 /// <param name="callback">The delegate/method to call when the session is created.</param>
108 public void CreateSession(int maxGamers, JoinedSessionDelegate callback)
109 {
110 Debug.Assert(mNetworkSession == null);
111
112 mJoinedSessionDelegate = callback;
113 NetworkSession.BeginCreate(NetworkSessionType.SystemLink, 1, maxGamers, CreateSessionEnd, null);
114 }
115 private void CreateSessionEnd(IAsyncResult result)
116 {
117 Debug.Assert(mNetworkSession == null);
118
119 try
120 {
121 mNetworkSession = NetworkSession.EndCreate(result);
122 mNetworkSession.AllowHostMigration = true;
123 mNetworkSession.AllowJoinInProgress = false;
124 mNetworkSession.GameStarted += new EventHandler<GameStartedEventArgs>(mNetworkSession_GameStarted);
125 }
126 catch (Exception e)
127 {
128 if (ErrorDelegate != null) ErrorDelegate(e, this);
129 return;
130 }
131 mJoinedSessionDelegate(mNetworkSession, this);
132 mJoinedSessionDelegate = null;
133 }
134
135
136 //gamestarted event
137 void mNetworkSession_GameStarted(object sender, GameStartedEventArgs e)
138 {
139 Reset();
140 }
141
142 /// <summary>
143 /// Determine whether or not the network game object is associated with any network session.
144 /// </summary>
145 /// <returns>True if there exists a NetworkSession; false otherwise.</returns>
146 public bool HasActiveSession
147 {
148 get
149 {
150 return mNetworkSession != null;
151 }
152 }
153
154
155 /// <summary>
156 /// Find available sessions to join. You should not already be in a session when
157 /// calling this method; call LeaveSession first.
158 /// </summary>
159 /// <param name="callback">The delegate/method to call when the search finishes.</param>
160 public void FindSessions(FoundSessionsDelegate callback)
161 {
162 Debug.Assert(mNetworkSession == null);
163
164 mFoundSessionsDelegate = callback;
165 NetworkSession.BeginFind(NetworkSessionType.SystemLink, 1, null, new AsyncCallback(FindSessionsEnd), null);
166 }
167 private void FindSessionsEnd(IAsyncResult result)
168 {
169 AvailableNetworkSessionCollection sessions;
170 try
171 {
172 sessions = NetworkSession.EndFind(result);
173 }
174 catch (Exception e)
175 {
176 if (ErrorDelegate != null) ErrorDelegate(e, this);
177 return;
178 }
179 mFoundSessionsDelegate(sessions, this);
180 mFoundSessionsDelegate = null;
181 }
182
183 /// <summary>
184 /// Join a network session found using FindSessions(). This is for joining a game that
185 /// somebody else has already started hosting. You must not already be in a session.
186 /// </summary>
187 /// <param name="availableSession">Pass the session object to try to join.</param>
188 /// <param name="callback">The delegate/method to call when the search finishes.</param>
189 public void JoinSession(AvailableNetworkSession availableSession, JoinedSessionDelegate callback)
190 {
191 Debug.Assert(mNetworkSession == null);
192
193 mJoinedSessionDelegate = callback;
194 NetworkSession.BeginJoin(availableSession, JoinSessionEnd, null);
195 }
196 private void JoinSessionEnd(IAsyncResult result)
197 {
198 Debug.Assert(mNetworkSession == null);
199
200 try
201 {
202 mNetworkSession = NetworkSession.EndJoin(result);
203 mNetworkSession.GameStarted += new EventHandler<GameStartedEventArgs>(mNetworkSession_GameStarted);
204 }
205 catch (Exception e)
206 {
207 if (ErrorDelegate != null) ErrorDelegate(e, this);
208 return;
209 }
210 mJoinedSessionDelegate(mNetworkSession, this);
211 mJoinedSessionDelegate = null;
212 }
213
214
215 /// <summary>
216 /// Leave and dispose of any currently associated network session. You will find yourself
217 /// back in the lobby. You must already be in a session to leave it.
218 /// </summary>
219 public void LeaveSession()
220 {
221 Debug.Assert(mNetworkSession != null);
222
223 mNetworkSession.Dispose();
224 mNetworkSession = null;
225 }
226
227
228 /// <summary>
229 /// Set up the network session to simulate 200ms latency and 10% packet loss.
230 /// </summary>
231 public void SimulateBadNetwork()
232 {
233 Debug.Assert(mNetworkSession != null);
234
235 mNetworkSession.SimulatedLatency = new TimeSpan(0, 0, 0, 0, 200);
236 mNetworkSession.SimulatedPacketLoss = 0.1f;
237 }
238
239
240 /// <summary>
241 /// Indicate that the game should begin (moving players from the lobby to the game).
242 /// You must call CreateSession() before calling this.
243 /// </summary>
244 public void StartGame()
245 {
246 Debug.Assert(mNetworkSession != null && mNetworkSession.IsHost &&
247 mNetworkSession.AllGamers.Count >= mGame.MinimumSupportedPlayers &&
248 mNetworkSession.IsEveryoneReady);
249
250 ForceStartGame();
251 }
252
253 /// <summary>
254 /// Indicate that the game should begin. This is like StartGame() without the sanity
255 /// checks. Use this for debugging.
256 /// </summary>
257 public void ForceStartGame()
258 {
259 mNetworkSession.StartGame();
260 mNetworkSession.ResetReady();
261
262 //Reset();
263 }
264
265
266 /// <summary>
267 /// Manages the network session and allows either the lobby or game to update.
268 /// </summary>
269 /// <param name="gameTime">Pass the time away.</param>
270 public void Update(GameTime gameTime)
271 {
272 if (mNetworkSession == null)
273 {
274 mLobby.Update(gameTime, this);
275 }
276 else
277 {
278 mNetworkSession.Update();
279 HandleIncomingPackets();
280
281 if (mNetworkSession.SessionState == NetworkSessionState.Lobby)
282 {
283 mLobby.Update(gameTime, this);
284 }
285 else if (mNetworkSession.SessionState == NetworkSessionState.Playing)
286 {
287 if (mGame.IsGameOver(LocalGamerInfo) || mGame.IsTerminated(LocalGamerInfo))
288 {
289 // TODO: Should support moving back to the session lobby.
290 LeaveSession();
291 return;
292 }
293
294 if (HaveNeededEvents)
295 {
296 if (IsLatencyAdjustmentFrame)
297 {
298 AdjustLatency();
299 mStallCount = 0;
300 }
301 mLocalEvents.AddRange(GetEventsFromInput());
302 SendLocalEvents();
303 ApplyEvents();
304 mGame.Update(mTargetTimeSpan);
305 }
306 else // Stall!
307 {
308 mStallCount++;
309
310 if (mStallCount % 60 == 0)
311 {
312 Console.WriteLine("Stalled for " + mStallCount + " frames.");
313 }
314
315 /*if (mStallCount > StallTimeout)
316 {
317 DropLostGamers();
318 mStallCount = 0;
319 }
320 else if (mStallCount == 1)
321 {
322 SendLocalEvents
323 }
324 else if (mStallCount % 60 == 0)
325 {
326 } TODO */
327 }
328 }
329 }
330 }
331
332 /// <summary>
333 /// Allows either the lobby or the game to draw, depending on the state
334 /// of the network connection and whether or not a game is in progress.
335 /// </summary>
336 /// <param name="gameTime">Pass the time away.</param>
337 /// <param name="spriteBatch">The sprite batch.</param>
338 public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
339 {
340 if (mNetworkSession == null)
341 {
342 mLobby.Draw(spriteBatch);
343 }
344 else
345 {
346 if (mNetworkSession.SessionState == NetworkSessionState.Lobby)
347 {
348 mLobby.Draw(spriteBatch);
349 }
350 else if (mNetworkSession.SessionState == NetworkSessionState.Playing)
351 {
352 mGame.Draw(spriteBatch);
353 }
354 }
355 }
356
357
358 /// <summary>
359 /// Get the chat messages that have been receive since the last time this
360 /// method was called.
361 /// </summary>
362 /// <returns>List container of the chat messages.</returns>
363 public List<ChatInfo> ReceiveChats()
364 {
365 List<ChatInfo> chats = mChatPackets;
366 mChatPackets = new List<ChatInfo>();
367 return chats;
368 }
369
370 /// <summary>
371 /// Send a chat message to all gamers in the session. You should already be
372 /// in a session before calling this method.
373 /// </summary>
374 /// <param name="message">The text of the message.</param>
375 public void SendChat(String message)
376 {
377 WriteChatPacket(message);
378 LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder);
379 }
380
381 /// <summary>
382 /// Send a chat message to a specific gamer in the session. You should already
383 /// be in a session before calling this method.
384 /// </summary>
385 /// <param name="message">The text of the message.</param>
386 /// <param name="recipient">The gamer to receive the message.</param>
387 public void SendChat(String message, NetworkGamer recipient)
388 {
389 WriteChatPacket(message);
390 LocalGamer.SendData(mPacketWriter, SendDataOptions.ReliableInOrder, recipient);
391 }
392
393 #endregion
394
395
396 // Private class variable members
397 #region Instance Variables
398
399 NetworkSession mNetworkSession;
400 PacketReader mPacketReader = new PacketReader();
401 PacketWriter mPacketWriter = new PacketWriter();
402
403 JoinedSessionDelegate mJoinedSessionDelegate;
404 FoundSessionsDelegate mFoundSessionsDelegate;
405
406 ILobby mLobby;
407 IDeterministicGame mGame;
408
409 List<ChatInfo> mChatPackets = new List<ChatInfo>();
410
411 List<EventInfo> mLocalEvents = new List<EventInfo>();
412 List<EventInfo> mLastLocalEvents = new List<EventInfo>();
413
414 List<Keys> mLastPressedKeys = new List<Keys>();
415 bool mLastLeftButtonPressed;
416 bool mLastRightButtonPressed;
417 bool mLastMiddleButtonPressed;
418 int mLastMousePositionX;
419 int mLastMousePositionY;
420
421 int mLatency;
422 long mNextLatencyAdjustmentFrame;
423 int mStallCount;
424 int mAverageOwd;
425
426 TimeSpan mTargetTimeSpan = new TimeSpan(166666);
427 public TimeSpan TargetTimeSpan
428 {
429 get
430 {
431 return mTargetTimeSpan;
432 }
433 }
434
435 Dictionary<byte, GamerInfo> mGamers;
436 GamerInfo[] GamerArray
437 {
438 get
439 {
440 GamerInfo[] gamerList = mGamers.Values.ToArray();
441 Array.Sort(gamerList, delegate(GamerInfo a, GamerInfo b)
442 {
443 return a.Gamer.Id.CompareTo(b.Gamer.Id);
444 });
445 return gamerList;
446 }
447 }
448 GamerInfo LocalGamerInfo
449 {
450 get
451 {
452 return mGamers[LocalGamer.Id];
453 }
454 }
455
456 #endregion
457
458
459 // Private types for the implementation of the network protocol
460 #region Private Types
461
462 enum PacketType
463 {
464 Chat = 1,
465 Event = 2,
466 Stall = 3
467 }
468
469 enum EventType
470 {
471 KeyDown = 1,
472 KeyUp = 2,
473 MouseDown = 3,
474 MouseUp = 4,
475 MouseMove = 5
476 }
477
478 enum MouseButton
479 {
480 Left = 1,
481 Right = 2,
482 Middle = 3
483 }
484
485 abstract class EventInfo
486 {
487 public NetworkGamer Gamer;
488 public long FrameOfApplication;
489
490 public EventInfo(NetworkGamer gamer, long frameNumber)
491 {
492 Gamer = gamer;
493 FrameOfApplication = frameNumber;
494 }
495
496 public abstract EventType Id
497 {
498 get;
499 }
500 }
501
502 class KeyboardEventInfo : EventInfo
503 {
504 public Keys Key;
505 public bool IsKeyDown;
506
507 public KeyboardEventInfo(NetworkGamer gamer, long frameNumber, Keys key, bool isDown)
508 : base(gamer, frameNumber)
509 {
510 Key = key;
511 IsKeyDown = isDown;
512 }
513
514 public override EventType Id
515 {
516 get { return IsKeyDown ? EventType.KeyDown : EventType.KeyUp; }
517 }
518 }
519
520 class MouseButtonEventInfo : EventInfo
521 {
522 public MouseButton Button;
523 public bool IsButtonDown;
524
525 public MouseButtonEventInfo(NetworkGamer gamer, long frameNumber, MouseButton button, bool isDown)
526 : base(gamer, frameNumber)
527 {
528 Button = button;
529 IsButtonDown = isDown;
530 }
531
532 public override EventType Id
533 {
534 get { return IsButtonDown ? EventType.MouseDown : EventType.MouseUp; }
535 }
536 }
537
538 class MouseMotionEventInfo : EventInfo
539 {
540 public int X;
541 public int Y;
542
543 public MouseMotionEventInfo(NetworkGamer gamer, long frameNumber, int x, int y)
544 : base(gamer, frameNumber)
545 {
546 X = x;
547 Y = y;
548 }
549
550 public override EventType Id
551 {
552 get { return EventType.MouseMove; }
553 }
554 }
555
556 class GamerInfo
557 {
558 public NetworkGamer Gamer;
559 public long HighestFrameNumber = 0;
560 public int StallCount = 0;
561 public int AverageOwd = 0;
562 public bool IsWaitedOn = false;
563 public List<EventInfo>[] Events = new List<EventInfo>[MaximumLatency];
564
565 public GamerInfo(NetworkGamer gamer)
566 {
567 Gamer = gamer;
568 }
569 }
570
571 const int MaximumLatency = 120;
572 const int StallTimeout = 900;
573
574 #endregion
575
576
577 // Private implementation methods of the network protocol
578 #region Private Implementation Methods
579
580 /// <summary>
581 /// Reinitialize the private variables in preparation for a new game to start.
582 /// </summary>
583 void Reset()
584 {
585 mLatency = 1;
586 mNextLatencyAdjustmentFrame = 1;
587 mStallCount = 0;
588 mAverageOwd = CurrentAverageOneWayDelay;
589
590 mGamers = new Dictionary<byte, GamerInfo>();
591 foreach (NetworkGamer gamer in NetworkGamers)
592 {
593 mGamers.Add(gamer.Id, new GamerInfo(gamer));
594 }
595
596 mGame.ResetGame(GamerArray, LocalGamerInfo);
597 }
598
599
600 void HandleIncomingPackets()
601 {
602 LocalNetworkGamer localGamer = LocalGamer;
603
604 while (localGamer.IsDataAvailable)
605 {
606 NetworkGamer sender;
607
608 localGamer.ReceiveData(mPacketReader, out sender);
609 GamerInfo senderInfo = mGamers[sender.Id];
610
611 PacketType packetId = (PacketType)mPacketReader.ReadByte();
612 switch (packetId)
613 {
614 case PacketType.Chat:
615
616 short messageLength = mPacketReader.ReadInt16();
617 char[] message = mPacketReader.ReadChars(messageLength);
618
619 ChatInfo chatPacket = new ChatInfo(sender, new String(message));
620 mChatPackets.Add(chatPacket);
621 break;
622
623 case PacketType.Event:
624
625 short stallCount = mPacketReader.ReadInt16();
626 short averageOwd = mPacketReader.ReadInt16();
627 int frameNumber = mPacketReader.ReadInt32();
628 byte numEvents = mPacketReader.ReadByte();
629
630 if (frameNumber <= senderInfo.HighestFrameNumber)
631 {
632 // we know about all these events, so don't bother reading them
633 break;
634 }
635
636 for (byte i = 0; i < numEvents; ++i)
637 {
638 EventInfo eventInfo = ReadEvent(mPacketReader, sender);
639
640 if (eventInfo != null && eventInfo.FrameOfApplication < senderInfo.HighestFrameNumber)
641 {
642 int index = EventArrayIndex;
643 if (senderInfo.Events[index] == null) senderInfo.Events[index] = new List<EventInfo>();
644 senderInfo.Events[index].Add(eventInfo);
645 }
646 }
647
648 senderInfo.StallCount = stallCount;
649 senderInfo.AverageOwd = averageOwd;
650 senderInfo.HighestFrameNumber = frameNumber;
651 break;
652
653 case PacketType.Stall:
654
655 byte numStalledPeers = mPacketReader.ReadByte();
656 byte[] stalledPeers = mPacketReader.ReadBytes(numStalledPeers);
657
658 // TODO
659
660 break;
661
662 default:
663
664 Console.WriteLine("Received unknown packet type: " + (int)packetId);
665 break;
666 }
667 }
668 }
669
670
671 int EventArrayIndex
672 {
673 get { return (int)(mGame.CurrentFrameNumber % MaximumLatency); }
674 }
675
676 EventInfo ReadEvent(PacketReader packetReader, NetworkGamer sender)
677 {
678 EventType eventId = (EventType)packetReader.ReadByte();
679 long frameNumber = packetReader.ReadInt32();
680
681 switch (eventId)
682 {
683 case EventType.KeyDown:
684
685 int keyCode1 = packetReader.ReadInt32();
686 return new KeyboardEventInfo(sender, frameNumber, (Keys)keyCode1, true);
687
688 case EventType.KeyUp:
689
690 int keyCode2 = packetReader.ReadInt32();
691 return new KeyboardEventInfo(sender, frameNumber, (Keys)keyCode2, false);
692
693 case EventType.MouseDown:
694
695 byte buttonId1 = packetReader.ReadByte();
696 return new MouseButtonEventInfo(sender, frameNumber, (MouseButton)buttonId1, true);
697
698 case EventType.MouseUp:
699
700 byte buttonId2 = packetReader.ReadByte();
701 return new MouseButtonEventInfo(sender, frameNumber, (MouseButton)buttonId2, false);
702
703 case EventType.MouseMove:
704
705 short x = packetReader.ReadInt16();
706 short y = packetReader.ReadInt16();
707 return new MouseMotionEventInfo(sender, frameNumber, x, y);
708
709 default:
710
711 Console.WriteLine("Received unknown event type: " + (int)eventId);
712 return null;
713 }
714 }
715
716
717 void WriteChatPacket(String message)
718 {
719 mPacketWriter.Write((byte)PacketType.Chat);
720 mPacketWriter.Write((short)message.Length);
721 mPacketWriter.Write(message.ToCharArray());
722 }
723
724 void WriteEventPacket(List<EventInfo> events)
725 {
726 mPacketWriter.Write((byte)PacketType.Event);
727 mPacketWriter.Write((short)mStallCount);
728 mPacketWriter.Write((short)mAverageOwd);
729 mPacketWriter.Write((int)(mGame.CurrentFrameNumber + mLatency));
730 mPacketWriter.Write((byte)events.Count);
731
732 foreach (EventInfo eventInfo in events)
733 {
734 mPacketWriter.Write((byte)eventInfo.Id);
735 mPacketWriter.Write((int)eventInfo.FrameOfApplication);
736
737 KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;
738 if (keyboardEventInfo != null)
739 {
740 mPacketWriter.Write((int)keyboardEventInfo.Key);
741 continue;
742 }
743
744 MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;
745 if (mouseButtonEventInfo != null)
746 {
747 mPacketWriter.Write((byte)mouseButtonEventInfo.Button);
748 continue;
749 }
750
751 MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;
752 if (mouseMotionEventInfo != null)
753 {
754 mPacketWriter.Write((short)mouseMotionEventInfo.X);
755 mPacketWriter.Write((short)mouseMotionEventInfo.Y);
756 continue;
757 }
758 }
759 }
760
761
762 bool IsLatencyAdjustmentFrame
763 {
764 get
765 {
766 return mNextLatencyAdjustmentFrame == mGame.CurrentFrameNumber;
767 }
768 }
769
770 void AdjustLatency()
771 {
772 Debug.Assert(IsLatencyAdjustmentFrame);
773
774 int maxStallCount = 0;
775 int maxAverageOwd = 0;
776
777 foreach (GamerInfo gamerInfo in GamerArray)
778 {
779 if (gamerInfo.StallCount > maxStallCount) maxStallCount = gamerInfo.StallCount;
780 if (gamerInfo.AverageOwd > maxAverageOwd) maxAverageOwd = gamerInfo.AverageOwd;
781 }
782
783 // DEBUG
784 int prevLatency = mLatency;
785
786 if (maxStallCount > 0)
787 {
788 mLatency += maxStallCount;
789 }
790 else
791 {
792 mLatency = (int)(0.6 * (double)(mLatency - maxAverageOwd) + 1.0);
793 }
794
795 // DEBUG OUTPUT
796 if (prevLatency != mLatency) Console.WriteLine("Latency readjusted to " + mLatency);
797
798 if (mLatency < 1) mLatency = 1;
799 if (mLatency > MaximumLatency) mLatency = MaximumLatency;
800
801 mNextLatencyAdjustmentFrame = mGame.CurrentFrameNumber + mLatency;
802 mAverageOwd = CurrentAverageOneWayDelay;
803
804 mLastLocalEvents = mLocalEvents;
805 mLocalEvents = new List<EventInfo>();
806 }
807
808
809
810 List<EventInfo> GetEventsFromInput()
811 {
812 List<EventInfo> events = new List<EventInfo>();
813
814 // 1. Find the keyboard differences; written by Peter.
815
816 KeyboardState keyState = Keyboard.GetState();
817
818 List<Keys> pressedKeys = new List<Keys>();
819 List<Keys> releasedKeys = new List<Keys>();
820
821 Keys[] pressedKeysArray = keyState.GetPressedKeys();
822 foreach (Keys k in pressedKeysArray)
823 {
824 if (!mLastPressedKeys.Contains(k)) pressedKeys.Add(k);
825 else mLastPressedKeys.Remove(k);
826 }
827
828 releasedKeys = mLastPressedKeys;
829
830 foreach (Keys key in pressedKeys)
831 {
832 events.Add(new KeyboardEventInfo(LocalGamer, mGame.CurrentFrameNumber, key, true));
833 }
834 foreach (Keys key in releasedKeys)
835 {
836 events.Add(new KeyboardEventInfo(LocalGamer, mGame.CurrentFrameNumber, key, false));
837 }
838
839 // 2. Find the mouse differences.
840
841 MouseState mouseState = Mouse.GetState();
842
843 bool leftButtonPressed = mouseState.LeftButton == ButtonState.Pressed;
844 if (leftButtonPressed != mLastLeftButtonPressed)
845 {
846 events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Left, leftButtonPressed));
847 }
848
849 bool rightButtonPressed = mouseState.LeftButton == ButtonState.Pressed;
850 if (rightButtonPressed != mLastRightButtonPressed)
851 {
852 events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Right, rightButtonPressed));
853 }
854
855 bool middleButtonPressed = mouseState.LeftButton == ButtonState.Pressed;
856 if (middleButtonPressed != mLastMiddleButtonPressed)
857 {
858 events.Add(new MouseButtonEventInfo(LocalGamer, mGame.CurrentFrameNumber, MouseButton.Middle, middleButtonPressed));
859 }
860
861 int mousePositionX = mouseState.X;
862 int mousePositionY = mouseState.Y;
863 if (mousePositionX != mLastMousePositionX || mousePositionY != mLastMousePositionY)
864 {
865 events.Add(new MouseMotionEventInfo(LocalGamer, mGame.CurrentFrameNumber, mousePositionX, mousePositionY));
866 }
867
868 // 3. Save the current peripheral state.
869
870 mLastPressedKeys = new List<Keys>(pressedKeysArray);
871 mLastLeftButtonPressed = leftButtonPressed;
872 mLastRightButtonPressed = rightButtonPressed;
873 mLastMiddleButtonPressed = middleButtonPressed;
874 mLastMousePositionX = mousePositionX;
875 mLastMousePositionY = mousePositionY;
876
877 return events;
878 }
879
880 void SendLocalEvents()
881 {
882 SendLocalEvents((NetworkGamer)null);
883 }
884
885 void SendLocalEvents(List<NetworkGamer> recipicents)
886 {
887 foreach (NetworkGamer gamer in recipicents)
888 {
889 SendLocalEvents(gamer);
890 }
891 }
892
893 void SendLocalEvents(NetworkGamer recipient)
894 {
895 List<EventInfo> events = new List<EventInfo>(mLocalEvents);
896 events.AddRange(mLastLocalEvents);
897
898 WriteEventPacket(events);
899
900 if (recipient != null)
901 {
902 LocalGamer.SendData(mPacketWriter, SendDataOptions.Reliable, recipient);
903 }
904 else
905 {
906 LocalGamer.SendData(mPacketWriter, SendDataOptions.None);
907 }
908 }
909
910
911 bool HaveNeededEvents
912 {
913 get
914 {
915 long currentFrame = mGame.CurrentFrameNumber;
916
917 foreach (GamerInfo gamerInfo in mGamers.Values)
918 {
919 if (gamerInfo.HighestFrameNumber < currentFrame) return false;
920 }
921
922 return true;
923 }
924 }
925
926 void ApplyEvents()
927 {
928 int index = EventArrayIndex;
929
930 foreach (GamerInfo gamerInfo in GamerArray)
931 {
932 if (gamerInfo.Events[index] == null) continue;
933
934 foreach (EventInfo eventInfo in gamerInfo.Events[index])
935 {
936 KeyboardEventInfo keyboardEventInfo = eventInfo as KeyboardEventInfo;
937 if (keyboardEventInfo != null)
938 {
939 mGame.ApplyKeyInput(gamerInfo, keyboardEventInfo.Key, keyboardEventInfo.IsKeyDown);
940 continue;
941 }
942
943 MouseButtonEventInfo mouseButtonEventInfo = eventInfo as MouseButtonEventInfo;
944 if (mouseButtonEventInfo != null)
945 {
946 mGame.ApplyMouseButtonInput(gamerInfo, mouseButtonEventInfo.IsButtonDown);
947 continue;
948 }
949
950 MouseMotionEventInfo mouseMotionEventInfo = eventInfo as MouseMotionEventInfo;
951 if (mouseMotionEventInfo != null)
952 {
953 mGame.ApplyMouseLocationInput(gamerInfo, mouseMotionEventInfo.X, mouseMotionEventInfo.Y);
954 continue;
955 }
956 }
957
958 gamerInfo.Events[index] = null;
959 }
960 }
961
962
963 int CurrentAverageOneWayDelay
964 {
965 get
966 {
967 Debug.Assert(mNetworkSession != null);
968
969 double numRemoteGamersTwice = 2 * mNetworkSession.RemoteGamers.Count;
970 double averageOwd = 0;
971
972 foreach (NetworkGamer gamer in mNetworkSession.RemoteGamers)
973 {
974 TimeSpan timeSpan = gamer.RoundtripTime;
975 averageOwd += timeSpan.TotalMilliseconds;
976 }
977
978 return (int)(averageOwd / numRemoteGamersTwice / 16.6666);
979 }
980 }
981
982 #endregion
983 }
984 }
This page took 0.088018 seconds and 4 git commands to generate.