/// <see cref="INetwork.JoinLobby"/> public ILobbyClient JoinLobby(LobbyInfo info, ILobbyListener listener) { if (this.closed) { throw new ObjectDisposedException("Network"); } if (listener == null) { throw new ArgumentNullException("listener"); } if (info == null) { throw new ArgumentNullException("info"); } if (this.localLobby == null && this.remoteLobby == null) { LobbyClient lobbyClient = CreateRemoteLobby_i(info, listener); lobbyClient.Disposed += this.LobbyDisposedHandler; this.remoteLobby = lobbyClient; return(this.remoteLobby); } else { return(null); } }
/// <summary> /// The starting function of the announcer thread. /// </summary> private void AnnounceProc() { while (!this.announcementFinished.WaitOne(NetworkingSystemConstants.ANNOUNCEMENT_FREQUENCY)) { LobbyInfo lobbyInfo = new LobbyInfo(this.announcedLobby.Id, "", this.announcedLobby.PortNum); if (null != this.customDataProvider) { lobbyInfo.CustomData = this.customDataProvider.CustomData; } RCPackage lobbyInfoPackage = lobbyInfo.Package; BroadcastPackage_i(lobbyInfoPackage); } /// Announce finished so we broadcast a FORMAT_LOBBY_INFO_VANISHED message. RCPackage lobbyVanishedPackage = RCPackage.CreateCustomDataPackage(Network.FORMAT_LOBBY_INFO_VANISHED); lobbyVanishedPackage.WriteString(0, this.announcedLobby.Id.ToString()); for (int i = 0; i < NetworkingSystemConstants.ANNOUNCEMENT_BROADCAST_MULTIPLICITY; i++) { /// Broadcast more than once because of possible package lost on UDP. BroadcastPackage_i(lobbyVanishedPackage); } }
/// <see cref="Network.CreateRemoteLobby_i"/> protected override LobbyClient CreateRemoteLobby_i(LobbyInfo info, ILobbyListener listener) { try { LobbyClient client = new LANLobbyClient(info, listener); return(client); } catch (Exception ex) { TraceManager.WriteExceptionAllTrace(ex, false); return(null); } }
/// <summary> /// Constructs a LobbyInfo object from an RCPackage. /// </summary> /// <param name="source">The package that contains the LobbyInfo data.</param> /// <returns>The contructed LobbyInfo or null if no LobbyInfo can be constructed from the given RCPackage.</returns> public static LobbyInfo FromRCPackage(RCPackage source) { if (null != source && source.IsCommitted && source.PackageFormat.ID == Network.FORMAT_LOBBY_INFO) { string idStr = source.ReadString(0); Guid id; if (!Guid.TryParse(idStr, out id)) { TraceManager.WriteAllTrace(string.Format("Unable to parse {0} as a GUID!", idStr), NetworkingSystemTraceFilters.INFO); return(null); } byte[] customDataBytes = source.ReadByteArray(3); int parsedBytes = 0; RCPackage customData = null; if (customDataBytes.Length > 0) { RCPackage.Parse(customDataBytes, 0, customDataBytes.Length, out parsedBytes); } if (customDataBytes.Length == 0 || (null != customData && customData.IsCommitted && parsedBytes == customDataBytes.Length)) { LobbyInfo retInfo = new LobbyInfo(id, /// ID source.ReadString(1), /// IPAddress source.ReadInt(2), /// PortNumber (customDataBytes.Length != 0) ? customData : null /// Custom infos about the lobby ); return(retInfo); } else { TraceManager.WriteAllTrace("LobbyInfo.FromRCPackage failed: unexpected CustomData package format!", NetworkingSystemTraceFilters.INFO); return(null); } } else { TraceManager.WriteAllTrace("LobbyInfo.FromRCPackage failed: unexpected package format!", NetworkingSystemTraceFilters.INFO); return(null); } }
/// <summary> /// Constructs a LobbyClient object. /// </summary> public LobbyClient(LobbyInfo info, ILobbyListener listener) { this.id = info.ID; this.listener = listener; this.memberCount = -1; this.clientID = -1; this.outgoingPackages = new List <RCPackage>(); this.outgoingPackageTargets = new List <int[]>(); IPAddress ipAddress; if (!IPAddress.TryParse(info.IPAddress, out ipAddress)) { throw new NetworkingSystemException("Unable to parse server IP address: " + info.IPAddress); } this.serverEndpoint = new IPEndPoint(ipAddress, info.PortNumber); this.connection = CreateConnection_i(this.serverEndpoint); this.stopConnectionManagerThread = new ManualResetEvent(false); this.connectionManagerThread = new RCThread(this.ConnectionManagerProc, "Networking"); this.connectionManagerThread.Start(); }
/// <summary> /// The starting function of the searcher thread. /// </summary> private void SearchProc() { while (!this.searchFinished.WaitOne(NetworkingSystemConstants.LOBBY_INFO_RECEIVE_FREQUENCY)) { /// Read an RCPackage from the network. IPAddress sender = IPAddress.Any; RCPackage announcementPackage = ReadPackage_i(ref sender); while (announcementPackage != null) { if (announcementPackage.PackageType == RCPackageType.CUSTOM_DATA_PACKAGE) { if (announcementPackage.PackageFormat.ID == Network.FORMAT_LOBBY_INFO) { /// Try to create a LobbyInfo object from the package. LobbyInfo info = LobbyInfo.FromRCPackage(announcementPackage); if (info != null && info.ID != Guid.Empty) { info.IPAddress = sender.ToString(); /// Search in the local registry. if (this.collectedInfos.ContainsKey(info.ID) && this.timers.ContainsKey(info.ID)) { /// If found we check if it has been changed since last check. bool changed = this.collectedInfos[info.ID].IPAddress.CompareTo(info.IPAddress) != 0 || this.collectedInfos[info.ID].PortNumber != info.PortNumber; /// Check for differences in the custom data. if (info.CustomData != null) { if (this.collectedInfos[info.ID].CustomData != null) { if (!RCPackage.IsEqual(this.collectedInfos[info.ID].CustomData, info.CustomData)) { changed = true; } } else { /// Custom data appeared. changed = true; } } else { if (this.collectedInfos[info.ID].CustomData != null) { /// Custom data disappeared. changed = true; } } this.collectedInfos[info.ID] = info; /// save the info this.timers[info.ID].Restart(); /// restarts it's timer /// notify the listener that the lobby has changed if (changed) { this.locator.LobbyChanged(info); } } else { /// If not found... this.collectedInfos.Add(info.ID, info); /// save the info this.timers.Add(info.ID, new Stopwatch()); /// create timer for the info this.timers[info.ID].Start(); /// start timer for the info /// notify the listener that a new lobby has been found this.locator.LobbyFound(info); } } } else if (announcementPackage.PackageFormat.ID == Network.FORMAT_LOBBY_INFO_VANISHED) { string idStr = announcementPackage.ReadString(0); Guid id; if (Guid.TryParse(idStr, out id) && id != Guid.Empty) { /// Search in the local registry. if (this.collectedInfos.ContainsKey(id) && this.timers.ContainsKey(id)) { LobbyInfo vanishedLobby = this.collectedInfos[id]; this.collectedInfos.Remove(id); this.timers.Remove(id); this.locator.LobbyVanished(vanishedLobby); } } } } announcementPackage = ReadPackage_i(ref sender); } /// end-while /// Check the timers. List <Guid> removedKeys = new List <Guid>(); foreach (KeyValuePair <Guid, Stopwatch> timer in this.timers) { if (timer.Value.ElapsedMilliseconds > NetworkingSystemConstants.LOBBY_INFO_TIMEOUT) { removedKeys.Add(timer.Key); } } foreach (Guid key in removedKeys) { LobbyInfo vanishedLobby = this.collectedInfos[key]; this.collectedInfos.Remove(key); this.timers.Remove(key); this.locator.LobbyVanished(vanishedLobby); } } }
/// <summary> /// Internal function to create a remote lobby. /// </summary> protected abstract LobbyClient CreateRemoteLobby_i(LobbyInfo info, ILobbyListener listener);