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