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