RemoteDebugCommand.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. //-----------------------------------------------------------------------------
  2. // RemoteDebugCommands.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. // Remote debugging doesn't work in MonoGame 3.8.4 because it relied on
  8. // Microsoft.Xna.Framework.Net which is obsolete.
  9. // This entire file has been disabled for MonoGame compatibility.
  10. #if FALSE // Disabled for MonoGame 3.8.4 compatibility
  11. using System;
  12. using System.Collections.Generic;
  13. using Microsoft.Xna.Framework.Net;
  14. using Microsoft.Xna.Framework;
  15. // using Microsoft.Xna.Framework.GamerServices; // Obsolete in MonoGame 3.8.4
  16. using System.Text.RegularExpressions;
  17. namespace HoneycombRush.GameDebugTools
  18. {
  19. /// <summary>
  20. /// Remote debug component.
  21. /// </summary>
  22. /// <remarks>
  23. /// This is the game component that supports remote debug command.
  24. /// When you use "remote" command on Windows side, it connect to Xbox 360 game via
  25. /// SystemLink.
  26. ///
  27. /// After you connected to Xbox 360, you can type debug command on Windows side that
  28. /// actually executed on Xbox 360 game. So, you can run debug command without
  29. /// connect a keyboard to the Xbox 360 console.
  30. ///
  31. /// To quit remote debug command more, simply type 'quit' command.
  32. /// </remarks>
  33. public class RemoteDebugCommand : GameComponent,
  34. IDebugCommandExecutioner, IDebugEchoListner
  35. {
  36. /// <summary>
  37. /// Sets/Get NetworkSession for Remote Debug Command.
  38. /// </summary>
  39. public NetworkSession NetworkSession { get; set; }
  40. /// <summary>
  41. /// Represents NetworkSession created by this component or not.
  42. /// </summary>
  43. public bool OwnsNetworkSession { get; private set; }
  44. const string StartPacketHeader = "RmtStart";
  45. const string ExecutePacketHeader = "RmtCmd";
  46. const string EchoPacketHeader = "RmtEcho";
  47. const string ErrorPacketHeader = "RmtErr";
  48. const string WarningPacketHeader = "RmtWrn";
  49. const string QuitPacketHeader = "RmtQuit";
  50. IDebugCommandHost commandHost;
  51. #if WINDOWS
  52. bool IsHost = false;
  53. #else
  54. bool IsHost = true;
  55. #endif
  56. Regex packetRe = new Regex(@"\$(?<header>[^$]+)\$:(?<text>.+)");
  57. PacketReader packetReader = new PacketReader();
  58. PacketWriter packetWriter = new PacketWriter();
  59. IAsyncResult asyncResult;
  60. enum ConnectionPahse
  61. {
  62. None,
  63. EnsureSignedIn,
  64. FindSessions,
  65. Joining,
  66. }
  67. ConnectionPahse phase = ConnectionPahse.None;
  68. public RemoteDebugCommand(Game game)
  69. : base(game)
  70. {
  71. commandHost =
  72. game.Services.GetService(typeof(IDebugCommandHost)) as IDebugCommandHost;
  73. if (!IsHost)
  74. {
  75. commandHost.RegisterCommand("remote", "Start remote command",
  76. ExecuteRemoteCommand);
  77. }
  78. }
  79. public override void Initialize()
  80. {
  81. if (IsHost)
  82. {
  83. commandHost.RegisterEchoListner(this);
  84. // Create network session if NetworkSession is not set.
  85. if (NetworkSession == null)
  86. {
  87. // GamerServicesDispatcher.WindowHandle = Game.Window.Handle;
  88. // GamerServicesDispatcher.Initialize(Game.Services);
  89. NetworkSession =
  90. NetworkSession.Create(NetworkSessionType.SystemLink, 1, 2);
  91. OwnsNetworkSession = true;
  92. }
  93. }
  94. base.Initialize();
  95. }
  96. /// <summary>
  97. /// Process received packet string.
  98. /// </summary>
  99. /// <remarks>You can call this method if you own network session on the game side.
  100. /// </remarks>
  101. /// <param name="packetString"></param>
  102. /// <returns>Processed this packet?</returns>
  103. public bool ProcessRecievedPacket(string packetString)
  104. {
  105. bool processed = false;
  106. Match mc = packetRe.Match(packetString);
  107. if (mc.Success)
  108. {
  109. string packetHeader = mc.Groups["header"].Value;
  110. string text = mc.Groups["text"].Value;
  111. switch (packetHeader)
  112. {
  113. case ExecutePacketHeader:
  114. commandHost.ExecuteCommand(text);
  115. processed = true;
  116. break;
  117. case EchoPacketHeader:
  118. commandHost.Echo(text);
  119. processed = true;
  120. break;
  121. case ErrorPacketHeader:
  122. commandHost.EchoError(text);
  123. processed = true;
  124. break;
  125. case WarningPacketHeader:
  126. commandHost.EchoWarning(text);
  127. processed = true;
  128. break;
  129. case StartPacketHeader:
  130. ConnectedToRemote();
  131. commandHost.Echo(text);
  132. processed = true;
  133. break;
  134. case QuitPacketHeader:
  135. commandHost.Echo(text);
  136. DisconnectedFromRemote();
  137. processed = true;
  138. break;
  139. }
  140. }
  141. return processed;
  142. }
  143. /// <summary>
  144. /// Update
  145. /// </summary>
  146. public override void Update(GameTime gameTime)
  147. {
  148. // Process different phases.
  149. switch (phase)
  150. {
  151. case ConnectionPahse.EnsureSignedIn:
  152. // GamerServicesDispatcher.Update();
  153. break;
  154. case ConnectionPahse.FindSessions:
  155. // GamerServicesDispatcher.Update();
  156. if (asyncResult.IsCompleted)
  157. {
  158. AvailableNetworkSessionCollection sessions =
  159. NetworkSession.EndFind(asyncResult);
  160. if (sessions.Count > 0)
  161. {
  162. asyncResult = NetworkSession.BeginJoin( sessions[0],
  163. null, null );
  164. commandHost.EchoError("Connecting to the host...");
  165. phase = ConnectionPahse.Joining;
  166. }
  167. else
  168. {
  169. commandHost.EchoError("Couldn't find a session.");
  170. phase = ConnectionPahse.None;
  171. }
  172. }
  173. break;
  174. case ConnectionPahse.Joining:
  175. // GamerServicesDispatcher.Update();
  176. if (asyncResult.IsCompleted)
  177. {
  178. NetworkSession = NetworkSession.EndJoin(asyncResult);
  179. NetworkSession.SessionEnded +=
  180. new EventHandler<NetworkSessionEndedEventArgs>(
  181. NetworkSession_SessionEnded);
  182. OwnsNetworkSession = true;
  183. commandHost.EchoError("Connected to the host.");
  184. phase = ConnectionPahse.None;
  185. asyncResult = null;
  186. ConnectedToRemote();
  187. }
  188. break;
  189. }
  190. // Update Network session.
  191. if (OwnsNetworkSession)
  192. {
  193. // GamerServicesDispatcher.Update();
  194. NetworkSession.Update();
  195. if (NetworkSession != null)
  196. {
  197. // Process received packets.
  198. foreach (LocalNetworkGamer gamer in NetworkSession.LocalGamers)
  199. {
  200. while (gamer.IsDataAvailable)
  201. {
  202. NetworkGamer sender;
  203. gamer.ReceiveData(packetReader, out sender);
  204. if (!sender.IsLocal)
  205. ProcessRecievedPacket(packetReader.ReadString());
  206. }
  207. }
  208. }
  209. }
  210. base.Update(gameTime);
  211. }
  212. /// <summary>
  213. /// Send remote debug command packet.
  214. /// </summary>
  215. void SendPacket(string header, string text)
  216. {
  217. if (NetworkSession != null)
  218. {
  219. packetWriter.Write("$" + header + "$:" + text);
  220. NetworkSession.LocalGamers[0].SendData(packetWriter,
  221. SendDataOptions.ReliableInOrder);
  222. }
  223. }
  224. /// <summary>
  225. /// Start remote debug command.
  226. /// </summary>
  227. void ConnectedToRemote()
  228. {
  229. DebugCommandUI commandUI = commandHost as DebugCommandUI;
  230. if (IsHost)
  231. {
  232. if ( commandUI != null )
  233. commandUI.Prompt = "[Host]>";
  234. }
  235. else
  236. {
  237. if (commandUI != null)
  238. commandUI.Prompt = "[Client]>";
  239. commandHost.PushExecutioner(this);
  240. SendPacket(StartPacketHeader, "Remote Debug Command Started!!");
  241. }
  242. commandHost.RegisterCommand("quit", "Quit from remote command",
  243. ExecuteQuitCommand);
  244. }
  245. /// <summary>
  246. /// End remote debug command.
  247. /// </summary>
  248. void DisconnectedFromRemote()
  249. {
  250. DebugCommandUI commandUI = commandHost as DebugCommandUI;
  251. if (commandUI != null)
  252. commandUI.Prompt = DebugCommandUI.DefaultPrompt;
  253. commandHost.UnregisterCommand("quit");
  254. if (!IsHost)
  255. {
  256. commandHost.PopExecutioner();
  257. if (OwnsNetworkSession)
  258. {
  259. NetworkSession.Dispose();
  260. NetworkSession = null;
  261. OwnsNetworkSession = false;
  262. }
  263. }
  264. }
  265. private void ExecuteRemoteCommand(IDebugCommandHost host, string command,
  266. IList<string> arguments)
  267. {
  268. if (NetworkSession == null)
  269. {
  270. try
  271. {
  272. // GamerServicesDispatcher.WindowHandle = Game.Window.Handle;
  273. // GamerServicesDispatcher.Initialize(Game.Services);
  274. }
  275. catch { }
  276. if (SignedInGamer.SignedInGamers.Count > 0)
  277. {
  278. commandHost.Echo("Finding available sessions...");
  279. asyncResult = NetworkSession.BeginFind(
  280. NetworkSessionType.SystemLink, 1, null, null, null);
  281. phase = ConnectionPahse.FindSessions;
  282. }
  283. else
  284. {
  285. host.Echo("Please signed in.");
  286. phase = ConnectionPahse.EnsureSignedIn;
  287. }
  288. }
  289. else
  290. {
  291. ConnectedToRemote();
  292. }
  293. }
  294. private void ExecuteQuitCommand(IDebugCommandHost host, string command,
  295. IList<string> arguments)
  296. {
  297. SendPacket(QuitPacketHeader, "End Remote Debug Command.");
  298. DisconnectedFromRemote();
  299. }
  300. public void ExecuteCommand(string command)
  301. {
  302. SendPacket(ExecutePacketHeader, command);
  303. }
  304. public void Echo(DebugCommandMessage messageType, string text)
  305. {
  306. switch (messageType)
  307. {
  308. case DebugCommandMessage.Standard:
  309. SendPacket(EchoPacketHeader, text );
  310. break;
  311. case DebugCommandMessage.Warning:
  312. SendPacket(WarningPacketHeader, text);
  313. break;
  314. case DebugCommandMessage.Error:
  315. SendPacket(ErrorPacketHeader, text);
  316. break;
  317. }
  318. }
  319. /// <summary>
  320. /// Handle the case host machine is gone.
  321. /// </summary>
  322. void NetworkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
  323. {
  324. DisconnectedFromRemote();
  325. commandHost.EchoWarning("Disconnected from the Host.");
  326. }
  327. }
  328. }
  329. #endif // FALSE - Disabled for MonoGame 3.8.4 compatibility