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