SystemLinkSessionManager.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Text;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace Microsoft.Xna.Framework.Net
  9. {
  10. internal static class SystemLinkSessionManager
  11. {
  12. private const int BroadcastPort = 31337;
  13. private static readonly List<AvailableNetworkSession> discoveredSessions = new List<AvailableNetworkSession>();
  14. public static Task AdvertiseSessionAsync(NetworkSession session, CancellationToken cancellationToken)
  15. {
  16. // Periodically broadcast session info on LAN until session is full or ended
  17. return Task.Run(async () =>
  18. {
  19. using (var udpClient = new UdpClient())
  20. {
  21. var endpoint = new IPEndPoint(IPAddress.Broadcast, BroadcastPort);
  22. while (!cancellationToken.IsCancellationRequested && session.AllGamers.Count < session.MaxGamers && session.sessionState != NetworkSessionState.Ended)
  23. {
  24. var propertiesBytes = session.SerializeSessionPropertiesBinary();
  25. var header = $"SESSION:{session.sessionId}:{session.MaxGamers}:{session.PrivateGamerSlots}:{session.Host?.Gamertag ?? "Host"}:";
  26. var headerBytes = Encoding.UTF8.GetBytes(header);
  27. var message = new byte[headerBytes.Length + propertiesBytes.Length];
  28. Buffer.BlockCopy(headerBytes, 0, message, 0, headerBytes.Length);
  29. Buffer.BlockCopy(propertiesBytes, 0, message, headerBytes.Length, propertiesBytes.Length);
  30. await udpClient.SendAsync(message, message.Length, endpoint);
  31. await Task.Delay(1000, cancellationToken); // Broadcast every second
  32. }
  33. }
  34. }, cancellationToken);
  35. }
  36. public static async Task<IEnumerable<AvailableNetworkSession>> DiscoverSessionsAsync(int maxLocalGamers, CancellationToken cancellationToken)
  37. {
  38. var sessions = new List<AvailableNetworkSession>();
  39. using (var udpClient = new UdpClient(BroadcastPort))
  40. {
  41. udpClient.EnableBroadcast = true;
  42. var receiveTask = udpClient.ReceiveAsync();
  43. var completedTask = await Task.WhenAny(receiveTask, Task.Delay(100, cancellationToken));
  44. if (completedTask == receiveTask)
  45. {
  46. var result = receiveTask.Result;
  47. var buffer = result.Buffer;
  48. // Find the header delimiter (the last colon of the header)
  49. int headerEnd = 0;
  50. int colonCount = 0;
  51. for (int i = 0; i < buffer.Length; i++)
  52. {
  53. if (buffer[i] == (byte)':')
  54. {
  55. colonCount++;
  56. if (colonCount == 5)
  57. {
  58. headerEnd = i + 1; // header ends after 5th colon
  59. break;
  60. }
  61. }
  62. }
  63. if (colonCount == 5)
  64. {
  65. var headerString = Encoding.UTF8.GetString(buffer, 0, headerEnd);
  66. var parts = headerString.Split(':');
  67. var sessionId = parts[1];
  68. var maxGamers = int.Parse(parts[2]);
  69. var privateSlots = int.Parse(parts[3]);
  70. var hostGamertag = parts[4];
  71. // Binary session properties start after headerEnd
  72. var propertiesBytes = new byte[buffer.Length - headerEnd];
  73. Buffer.BlockCopy(buffer, headerEnd, propertiesBytes, 0, propertiesBytes.Length);
  74. var dummySession = new NetworkSession(NetworkSessionType.SystemLink, maxGamers, privateSlots, false, sessionId);
  75. dummySession.DeserializeSessionPropertiesBinary(propertiesBytes);
  76. var sessionProperties = dummySession.SessionProperties as Dictionary<string, object>;
  77. sessions.Add(new AvailableNetworkSession(
  78. sessionName: "SystemLinkSession",
  79. hostGamertag: hostGamertag,
  80. currentGamerCount: 1,
  81. openPublicGamerSlots: maxGamers - 1,
  82. openPrivateGamerSlots: privateSlots,
  83. sessionType: NetworkSessionType.SystemLink,
  84. sessionProperties: sessionProperties,
  85. sessionId: sessionId));
  86. }
  87. }
  88. }
  89. return sessions;
  90. }
  91. public static async Task<NetworkSession> JoinSessionAsync(AvailableNetworkSession availableSession, CancellationToken cancellationToken)
  92. {
  93. // For demo: create a new session instance
  94. await Task.Delay(10, cancellationToken);
  95. var session = new NetworkSession(NetworkSessionType.SystemLink,
  96. availableSession.OpenPublicGamerSlots + availableSession.CurrentGamerCount,
  97. availableSession.OpenPrivateGamerSlots,
  98. false,
  99. availableSession.SessionId);
  100. session.sessionState = NetworkSessionState.Lobby;
  101. // Copy session properties from AvailableNetworkSession to NetworkSession
  102. foreach (var kvp in availableSession.SessionProperties)
  103. session.SessionProperties[kvp.Key] = kvp.Value;
  104. return session;
  105. }
  106. }
  107. }