/// <summary> /// Creates an RCCommand object from the given RCPackage. /// </summary> /// <param name="cmdPackage">The RCPackage to be deserialized.</param> /// <returns>The created RCCommand.</returns> public static RCCommand FromPackage(RCPackage cmdPackage) { if (cmdPackage == null) { throw new ArgumentNullException("cmdPackage"); } if (!cmdPackage.IsCommitted) { throw new ArgumentException("The incoming package is not committed!", "cmdPackage"); } if (cmdPackage.PackageFormat.ID != RCCommand.COMMAND_PACKAGEFORMAT) { throw new ArgumentException("The incoming package is not a command package!", "cmdPackage"); } RCNumVector targetPosition = RCNumVector.Undefined; int targetPositionX = cmdPackage.ReadInt(2); int targetPositionY = cmdPackage.ReadInt(3); if (targetPositionX != -1 && targetPositionY != -1) { targetPosition = new RCNumVector(new RCNumber(targetPositionX), new RCNumber(targetPositionY)); } return(new RCCommand( cmdPackage.ReadString(0), cmdPackage.ReadIntArray(1), targetPosition, cmdPackage.ReadInt(4), cmdPackage.ReadString(5))); }
/// <see cref="ITileSetLoader.LoadTileSet"/> public ITileSet LoadTileSet(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } int parsedBytes; RCPackage package = RCPackage.Parse(data, 0, data.Length, out parsedBytes); if (!package.IsCommitted) { throw new ArgumentException("TileSet data package is not committed!", "data"); } if (package.PackageType != RCPackageType.CUSTOM_DATA_PACKAGE) { throw new ArgumentException("TileSet data package must be RCPackageType.CUSTOM_DATA_PACKAGE!", "data"); } if (package.PackageFormat.ID != PackageFormats.TILESET_FORMAT) { throw new ArgumentException("Format of TileSet data package must be RC.Engine.Maps.TileSetFormat!", "data"); } TileSet tileset = XmlTileSetReader.Read(package.ReadString(0), package.ReadString(1)); return(tileset); }
/// <summary> /// Called when a NETWORK_CUSTOM_PACKAGE has arrived from the lobby. /// </summary> /// <remarks>Must be implemented at both server and client side.</remarks> public virtual void PackageArrivedHdl(int timestamp, RCPackage package, int senderID) { if (IsSimulationRunning_i()) { /// Package arrived during simulation stage must be handled. if (package.PackageFormat.ID == DssRoot.DSS_COMMAND) { if (!CommandPackageArrived(package, senderID)) { this.root.SimulationMgr.SimulationStageError(string.Format("Processing incoming DSS_COMMAND package failed. Sender: {0}. Package: {1}", senderID, package.ToString()), new byte[] { }); } } else if (package.PackageFormat.ID == DssRoot.DSS_COMMIT) { if (!this.root.SimulationMgr.RegisterCommit(package, senderID)) { this.root.SimulationMgr.SimulationStageError(string.Format("Processing incoming DSS_COMMIT package failed. Sender: {0}. Package: {1}", senderID, package.ToString()), new byte[] { }); } } else if (package.PackageFormat.ID == DssRoot.DSS_COMMIT_ANSWER) { if (!this.root.SimulationMgr.RegisterCommitAnswer(package, senderID)) { this.root.SimulationMgr.SimulationStageError(string.Format("Processing incoming DSS_COMMIT_ANSWER package failed. Sender: {0}. Package: {1}", senderID, package.ToString()), new byte[] { }); } } else if (package.PackageFormat.ID == DssRoot.DSS_LEAVE) { if (this.root.SimulationMgr.RegisterLeaveMessage(package, senderID)) { this.root.OperatorLeftSimulationStage(senderID); } else { this.root.SimulationMgr.SimulationStageError(string.Format("Processing incoming DSS_LEAVE package failed. Sender: {0}. Package: {1}", senderID, package.ToString()), new byte[] { }); } } else if (package.PackageFormat.ID == DssRoot.DSS_SIM_ERROR) { string errorDescr = package.ReadString(0); byte[] customData = package.ReadByteArray(1); this.root.SimulationMgr.SimulationStageErrorReceived(string.Format("DSS_SIM_ERROR received from operator-{0}: {1}", senderID, errorDescr), customData); } else { this.root.SimulationMgr.SimulationStageError(string.Format("Unexpected package arrived from operator-{0}: {1}", senderID, package.ToString()), new byte[] { }); } } else { /// Package arrived during setup stage is not allowed. PackageArrivedDuringSetupStage_i(package, senderID); } }
/// <summary> /// Creates a MapHeader structure from the given RCPackage. /// </summary> /// <param name="package">The RCPackage that contains the map header informations.</param> /// <returns>The created MapHeader structure.</returns> public static MapHeader FromPackage(RCPackage package) { if (package == null) { throw new ArgumentNullException("package"); } if (!package.IsCommitted) { throw new ArgumentException("The header package is not committed!", "package"); } if (package.PackageType != RCPackageType.CUSTOM_DATA_PACKAGE) { throw new ArgumentException("Invalid package type!", "package"); } if (package.PackageFormat.ID != MapFileFormat.MAP_HEADER) { throw new ArgumentException("Invalid package format!", "package"); } MapHeader header = new MapHeader(); header.appVersion = new Version(package.ReadInt(0), package.ReadInt(1), package.ReadInt(2), package.ReadInt(3)); header.mapName = package.ReadString(4); header.tilesetName = package.ReadString(5); header.mapSize = new RCIntVector(package.ReadShort(6), package.ReadShort(7)); header.maxPlayers = package.ReadByte(8); header.checksumList = new List <int>(package.ReadIntArray(9)); if (header.mapName == null) { throw new MapException("Map name information is missing!"); } if (header.tilesetName == null) { throw new MapException("Tileset name information is missing!"); } if (header.mapSize.X <= 0 || header.mapSize.Y <= 0) { throw new MapException("Map size cannot be negative or 0!"); } if (header.maxPlayers <= 0) { throw new MapException("Maximum number of players cannot be negative or 0!"); } return(header); }
/// <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> /// /// </summary> /// <param name="package"></param> private void CreateJoinRow(RCPackage package) { string runningThreadName = package.ReadString(1); string waitingThreadName = package.ReadString(3); long timestamp = package.ReadLong(4); if (!this.threadsToColumns.ContainsKey(runningThreadName)) { int idxOfCol = this.gridLog.Columns.Add(runningThreadName, runningThreadName); this.threadsToColumns.Add(runningThreadName, idxOfCol); } if (!this.threadsToColumns.ContainsKey(waitingThreadName)) { int idxOfCol = this.gridLog.Columns.Add(waitingThreadName, waitingThreadName); this.threadsToColumns.Add(waitingThreadName, idxOfCol); } object[] rowContent = new object[this.threadsToColumns.Count]; rowContent[this.threadsToColumns[runningThreadName]] = "THREAD_FINISH"; rowContent[this.threadsToColumns[waitingThreadName]] = "THREAD_JOIN"; int idxOfRow = this.gridLog.Rows.Add(rowContent); this.gridLog.Rows[idxOfRow].HeaderCell.Value = timestamp.ToString(); DataGridViewCell cellOfRunning = this.gridLog[this.threadsToColumns[runningThreadName], idxOfRow]; DataGridViewCell cellOfWaiting = this.gridLog[this.threadsToColumns[waitingThreadName], idxOfRow]; cellOfRunning.Style.BackColor = Color.LightPink; cellOfWaiting.Style.BackColor = Color.LightPink; if (!this.doubleSelections.ContainsKey(cellOfRunning)) { this.doubleSelections.Add(cellOfRunning, cellOfWaiting); } if (!this.doubleSelections.ContainsKey(cellOfWaiting)) { this.doubleSelections.Add(cellOfWaiting, cellOfRunning); } }
/// <summary> /// /// </summary> /// <param name="package"></param> private void CreateForkRow(RCPackage package) { string newThreadName = package.ReadString(1); string parentThreadName = package.ReadString(3); long timestamp = package.ReadLong(4); if (!this.threadsToColumns.ContainsKey(newThreadName)) { int idxOfCol = this.gridLog.Columns.Add(newThreadName, newThreadName); this.threadsToColumns.Add(newThreadName, idxOfCol); } if (!this.threadsToColumns.ContainsKey(parentThreadName)) { int idxOfCol = this.gridLog.Columns.Add(parentThreadName, parentThreadName); this.threadsToColumns.Add(parentThreadName, idxOfCol); } object[] rowContent = new object[this.threadsToColumns.Count]; rowContent[this.threadsToColumns[newThreadName]] = "THREAD_START"; rowContent[this.threadsToColumns[parentThreadName]] = "THREAD_FORK"; int idxOfRow = this.gridLog.Rows.Add(rowContent); this.gridLog.Rows[idxOfRow].HeaderCell.Value = timestamp.ToString(); DataGridViewCell cellOfNew = this.gridLog[this.threadsToColumns[newThreadName], idxOfRow]; DataGridViewCell cellOfParent = this.gridLog[this.threadsToColumns[parentThreadName], idxOfRow]; cellOfNew.Style.BackColor = Color.LightGreen; cellOfParent.Style.BackColor = Color.LightGreen; if (!this.doubleSelections.ContainsKey(cellOfNew)) { this.doubleSelections.Add(cellOfNew, cellOfParent); } if (!this.doubleSelections.ContainsKey(cellOfParent)) { this.doubleSelections.Add(cellOfParent, cellOfNew); } }
/// <summary> /// /// </summary> /// <param name="package"></param> private void CreateExceptionRow(RCPackage package) { string threadName = package.ReadString(1); long timestamp = package.ReadLong(2); bool isFatal = (package.ReadByte(3) == (byte)0x00) ? false : true; string ex = package.ReadString(4); if (!this.threadsToColumns.ContainsKey(threadName)) { int idxOfCol = this.gridLog.Columns.Add(threadName, threadName); this.threadsToColumns.Add(threadName, idxOfCol); } object[] rowContent = new object[this.threadsToColumns.Count]; rowContent[this.threadsToColumns[threadName]] = isFatal ? "FATAL_EXCEPTION" : "EXCEPTION"; int idxOfRow = this.gridLog.Rows.Add(rowContent); this.gridLog.Rows[idxOfRow].HeaderCell.Value = timestamp.ToString(); DataGridViewCell cellOfException = this.gridLog[this.threadsToColumns[threadName], idxOfRow]; cellOfException.Style.BackColor = isFatal ? Color.Red : Color.Yellow; if (isFatal) { if (!this.fatalExceptions.ContainsKey(cellOfException)) { this.fatalExceptions.Add(cellOfException, ex); } } else { if (!this.normalExceptions.ContainsKey(cellOfException)) { this.normalExceptions.Add(cellOfException, ex); } } }
/// <summary> /// /// </summary> /// <param name="package"></param> private void CreateEventFormatRow(RCPackage package) { string threadName = package.ReadString(1); long timestamp = package.ReadLong(2); string evt = package.ReadString(3); if (!this.threadsToColumns.ContainsKey(threadName)) { int idxOfCol = this.gridLog.Columns.Add(threadName, threadName); this.threadsToColumns.Add(threadName, idxOfCol); } object[] rowContent = new object[this.threadsToColumns.Count]; rowContent[this.threadsToColumns[threadName]] = evt; int idxOfRow = this.gridLog.Rows.Add(rowContent); this.gridLog.Rows[idxOfRow].HeaderCell.Value = timestamp.ToString(); DataGridViewCell cellOfEvent = this.gridLog[this.threadsToColumns[threadName], idxOfRow]; cellOfEvent.Style.BackColor = Color.LightGray; }
/// <see cref="ILobbyListener.ControlPackageArrived"/> public void ControlPackageArrived(RCPackage package, int senderID) { if (this.InvokeRequired) { /// Invoke this function from the UI thread. this.Invoke(new InternalArrivedFromClientCallback(this.ControlPackageArrived), new object[2] { package, senderID }); } else { /// Normal invoke. if (senderID >= 0 && senderID < this.textBoxes.Length && package.PackageFormat.ID == MY_FORMAT) { this.textChangingFromNetwork = true; this.textBoxes[senderID].Text = package.ReadString(0); this.textChangingFromNetwork = false; UpdateControls(); } } }
/// <see cref="ILobbyListener.ControlPackageArrived"/> public void ControlPackageArrived(RCPackage package) { if (this.InvokeRequired) { /// Invoke this function from the UI thread. this.Invoke(new InternalArrivedFromServerCallback(this.ControlPackageArrived), new object[1] { package }); } else { /// Normal invoke. if (package.PackageFormat.ID == MY_FORMAT) { this.textChangingFromNetwork = true; this.textBoxes[0].Text = package.ReadString(0); this.textChangingFromNetwork = false; UpdateControls(); } } }
/// <summary> /// Registers the given DSS_LEAVE message arrived from the given operator. /// </summary> /// <param name="leaveMsg">The arrived DSS_LEAVE message.</param> /// <param name="senderID">The sender operator.</param> /// <returns>True in case of success, false otherwise.</returns> public bool RegisterLeaveMessage(RCPackage leaveMsg, int senderID) { if (!this.initialized) { throw new DssException("DssSimulationMgr is uninitialized!"); } /// If we are currently finishing the simulation --> do nothing if (this.hostLeft) { return(true); } if (leaveMsg == null || !leaveMsg.IsCommitted) { throw new ArgumentException("leaveMsg"); } if (senderID == this.root.IdOfThisPeer) { throw new DssException("Unexpected DSS_LEAVE sender!"); } if (senderID < 0 || senderID >= this.root.OpCount) { throw new ArgumentException("senderID"); } if (leaveMsg.PackageFormat.ID != DssRoot.DSS_LEAVE) { /// Package format error. return(false); } string reason = leaveMsg.ReadString(0); byte[] customData = leaveMsg.ReadByteArray(1); TraceManager.WriteAllTrace(string.Format("DSS_LEAVE: sender={0}, reason= {1}", senderID, reason), DssTraceFilters.SIMULATION_INFO); /// Set the corresponding operator flag to false. this.operatorFlags[senderID] = false; if (senderID > 0) { /// GUEST-leave /// Unregister all CommitMonitors that became unnecessary. List <int> commitAwTicketsToUnreg = new List <int>(); foreach (KeyValuePair <int, CommitMonitor> monitor in this.commitAwMonitors) { monitor.Value.Refresh(); if (monitor.Value.IsCommitAnswered) { commitAwTicketsToUnreg.Add(monitor.Value.Ticket); } } foreach (int ticket in commitAwTicketsToUnreg) { UnregisterCommitMonitor(ticket); } /// Try to register the leave of operator to the nextRound. if (!this.nextRound.Leave(senderID)) { /// If failed, try to register to the nextNextRound. if (!this.nextNextRound.Leave(senderID)) { /// If failed, try to register to the nextNextNextRound. if (!this.nextNextNextRound.Leave(senderID)) { /// Error: unable to register TraceManager.WriteAllTrace(string.Format("Unable to register the leave of operator-{0}.", senderID), DssTraceFilters.SIMULATION_ERROR); return(false); } } } /// Now check whether the next round has become committed with this leave message. if (this.waitingForCommit && this.nextRound.IsCommitted) { TraceManager.WriteAllTrace("WAITING FOR COMMIT END (guest left)", DssTraceFilters.SIMULATION_INFO); /// The missing commit has arrived, so we can continue the simulation this.waitingForCommit = false; /// Compute the scheduled time for the next frame int nextFrameStartTime = this.currentRound.BaseTime + (this.currentRound.CurrentFrameIndex + 1) * this.currentRound.TargetFrameTime; SendCommit(); SwapRounds(); /// Schedule the next frame. SetNextFrameExecutionTime(Math.Max(nextFrameStartTime, DssRoot.Time)); } } else { /// HOST-leave /// Stop the timers UnregisterAllCommitMonitors(); StopCommitTimeoutClock(); if (this.waitingForCommit && this.nextRound.IsCommitted) { /// Can continue with the next round TraceManager.WriteAllTrace("WAITING FOR COMMIT END (host left)", DssTraceFilters.SIMULATION_INFO); /// The missing commit has arrived, so we can continue the simulation this.waitingForCommit = false; /// Compute the scheduled time for the next frame int nextFrameStartTime = this.currentRound.BaseTime + (this.currentRound.CurrentFrameIndex + 1) * this.currentRound.TargetFrameTime; SendCommit(); SwapRounds(); /// Schedule the next frame. SetNextFrameExecutionTime(Math.Max(nextFrameStartTime, DssRoot.Time)); } else if (this.waitingForCommit && !this.nextRound.IsCommitted) { /// Cannot continue with the next round --> notify the client module and exit the event loop NotifyClientAboutLeavingGuests(this.nextRound); NotifyClientAboutLeavingGuests(this.nextNextRound); NotifyClientAboutLeavingGuests(this.nextNextNextRound); this.root.SimulatorIface.HostLeftDssDuringSim(); this.root.EventQueue.ExitEventLoop(); } this.hostLeft = true; } return(true); }
/// <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> /// Called when a control packages arrived from the host during setup stage. /// </summary> /// <param name="package">The arrived control package.</param> public void SetupStageCtrlPackage(RCPackage package) { if (this.sm.CurrentState == this.WaitingConnectionACK) { if (package.PackageFormat.ID == DssRoot.DSS_CTRL_CONN_ACK) { int otherMajor = package.ReadInt(0); int otherMinor = package.ReadInt(1); int otherBuild = package.ReadInt(2); int otherRevision = package.ReadInt(3); if (otherMajor >= 0 && otherMinor >= 0 && otherBuild >= 0 && otherRevision >= 0) { Version otherVer = new Version(otherMajor, otherMinor, otherBuild, otherRevision); if (DssRoot.IsCompatibleVersion(otherVer)) { this.WaitingConnectionACK_WaitingSetupStepRQ.Fire(); this.controller.ExecuteFirings(); return; } else { TraceManager.WriteAllTrace(string.Format("Incompatible with host version: {0} (RC.DssServices)", otherVer), DssTraceFilters.SETUP_STAGE_ERROR); SetupStageError(); return; } } else { TraceManager.WriteAllTrace("Unable to parse version information!", DssTraceFilters.SETUP_STAGE_ERROR); SetupStageError(); return; } } /// end-if (package.PackageFormat.ID == DssRoot.DSS_CTRL_CONN_ACK) else if (package.PackageFormat.ID == DssRoot.DSS_CTRL_CONN_REJECT) { TraceManager.WriteAllTrace(string.Format("Connection request rejected by the host! Reason: {0}", package.ReadString(0)), DssTraceFilters.SETUP_STAGE_ERROR); SetupStageError(); return; } else { TraceManager.WriteAllTrace("Unexpected answer from host to connection request!", DssTraceFilters.SETUP_STAGE_ERROR); SetupStageError(); return; } } else if (this.sm.CurrentState == this.WaitingSetupStepRQ) { if (package.PackageFormat.ID == DssRoot.DSS_LEAVE) { /// The host left the DSS this.guestRoot.SetupIface.HostLeftDss(); StopTimeouts(); this.guestRoot.EventQueue.ExitEventLoop(); return; } /// end-if (package.PackageFormat.ID == DssRoot.DSS_LEAVE) else if (package.PackageFormat.ID == DssRoot.DSS_CTRL_DROP_GUEST) { /// The current guest has been dropped out of the DSS by the host. this.guestRoot.SetupIface.DroppedByHost(); StopTimeouts(); this.guestRoot.EventQueue.ExitEventLoop(); return; } /// end-if (package.PackageFormat.ID == DssRoot.DSS_CTRL_DROP_GUEST) else if (package.PackageFormat.ID == DssRoot.DSS_CTRL_START_SIMULATION) { int[] leftList = null; int[] lostList = null; bool[] opFlags = null; if (ParseStartSimPackage(package, out leftList, out lostList, out opFlags)) { StopTimeouts(); CallNotificationMethods(leftList, lostList); this.guestRoot.SetupIface.SimulationStarted(); this.opFlagsTmp = opFlags; this.WaitingSetupStepRQ_Simulating.Fire(); this.controller.ExecuteFirings(); return; } else { SetupStageError(); return; } } /// end-if (package.PackageFormat.ID == DssRoot.DSS_CTRL_START_SIMULATION) else { this.guestRoot.Step.IncomingPackage(package); if (this.guestRoot.Step.State == SetupStepState.READY) { /// Setup step request arrived. this.WaitingSetupStepRQ_SendingSetupStepAW.Fire(); this.controller.ExecuteFirings(); return; } else if (this.guestRoot.Step.State == SetupStepState.ERROR) { /// Setup step request error. SetupStageError(); return; } else { /// Setup step request not finished yet, more packages to wait. return; } } } /// end-if (this.sm.CurrentState == this.WaitingSetupStepRQ) else { /// Go to error state if the package cannot be handled until now. SetupStageError(); return; } }
/// <summary> /// This function is called when a control package arrives at setup stage. /// </summary> /// <param name="package">The arrived control package.</param> public void SetupStageCtrlPackage(RCPackage package) { bool error = false; if (this.sm.CurrentState == this.WaitingConnectionRQ) { if (package.PackageFormat.ID == DssRoot.DSS_CTRL_CONN_REQUEST) { RCPackage rejPackage = null; int otherMajor = package.ReadInt(0); int otherMinor = package.ReadInt(1); int otherBuild = package.ReadInt(2); int otherRevision = package.ReadInt(3); if (otherMajor >= 0 && otherMinor >= 0 && otherBuild >= 0 && otherRevision >= 0) { Version otherVer = new Version(otherMajor, otherMinor, otherBuild, otherRevision); if (DssRoot.IsCompatibleVersion(otherVer)) { /// We send back a DSS_CTRL_CONN_ACK package. RCPackage ackPackage = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_CTRL_CONN_ACK); ackPackage.WriteInt(0, DssRoot.APPLICATION_VERSION.Major); ackPackage.WriteInt(1, DssRoot.APPLICATION_VERSION.Minor); ackPackage.WriteInt(2, DssRoot.APPLICATION_VERSION.Build); ackPackage.WriteInt(3, DssRoot.APPLICATION_VERSION.Revision); this.manager.HostRoot.Lobby.SendControlPackage(ackPackage, this.channel.Index + 1); this.WaitingConnectionRQ_SendingSetupStepRQ.Fire(); } else { /// We send back a DSS_CTRL_CONN_REJECT package rejPackage = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_CTRL_CONN_REJECT); string reason = string.Format("Incompatible with host version: {0} (RC.DssServices)", DssRoot.APPLICATION_VERSION.ToString()); rejPackage.WriteString(0, reason); rejPackage.WriteByteArray(1, new byte[0]); } } else { /// We create a DSS_CTRL_CONN_REJECT package rejPackage = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_CTRL_CONN_REJECT); rejPackage.WriteString(0, "Unable to parse version information!"); rejPackage.WriteByteArray(1, new byte[0]); } /// We send back a DSS_CTRL_CONN_REJECT package if necessary. if (rejPackage != null && rejPackage.IsCommitted) { this.manager.HostRoot.Lobby.SendControlPackage(rejPackage, this.channel.Index + 1); error = true; } } /// end-if (package.PackageFormat.ID == DssRoot.DSS_CTRL_CONN_REQUEST) } /// end-if (this.sm.CurrentState == this.WaitingConnectionRQ) else if (this.sm.CurrentState == this.WaitingSetupStepAW) { if (package.PackageFormat.ID == DssRoot.DSS_LEAVE) { string leaveReason = package.ReadString(0); string trcMsg = string.Format("Guest-{0} has left the DSS. Reason: {1}", this.channel.Index, leaveReason.Length != 0 ? leaveReason : "-"); TraceManager.WriteAllTrace(trcMsg, DssTraceFilters.SETUP_STAGE_INFO); this.WaitingSetupStepAW_Inactive.Fire(); this.channel.GuestLeaveSetupStage(); } /// end-if (package.PackageFormat.ID == DssRoot.DSS_LEAVE) else { SetupStep currentStep = this.manager.HostRoot.GetStep(this.channel.Index); currentStep.IncomingPackage(package); if (currentStep.State == SetupStepState.READY) { /// Setup step answer arrived. this.WaitingSetupStepAW_SendingSetupStepRQ.Fire(); } else if (currentStep.State == SetupStepState.ERROR) { /// Setup step answer error. error = true; } else { /// Setup step answer not finished yet, more packages to wait. } } } /// end-if (this.sm.CurrentState == this.WaitingSetupStepAW) if (error) { /// Go to error state if the package cannot be handled until now. SetupStageError(); this.channel.SetupStageError(); return; } }