Пример #1
0
        /// <summary>
        /// Call this function when an error occurs during the simulation stage.
        /// </summary>
        /// <param name="reason">The reason of the error.</param>
        /// <param name="customData">Custom data about the error.</param>
        public void SimulationStageError(string reason, byte[] customData)
        {
            if (!this.initialized)
            {
                throw new DssException("DssSimulationMgr is uninitialized!");
            }

            /// If we are currently finishing the simulation --> do nothing
            if (this.hostLeft)
            {
                return;
            }

            /// Stop the alarm clocks
            StopCommitTimeoutClock();
            StopSimulationFrameClock();
            UnregisterAllCommitMonitors();

            /// Send the DSS_SIM_ERROR message to the others
            RCPackage errPackage = RCPackage.CreateNetworkCustomPackage(DssRoot.DSS_SIM_ERROR);

            errPackage.WriteString(0, reason);
            errPackage.WriteByteArray(1, customData);
            this.root.LobbyIface.SendPackage(errPackage);

            /// Quit from the DSS immediately
            this.root.SimulatorIface.SimulationError(reason, customData);
            this.root.EventQueue.ExitEventLoop();
        }
Пример #2
0
        /// <summary>
        /// Sends reports about the given line states to all connected clients and to the listener of this server.
        /// </summary>
        private void SendLineStateReports(LobbyLineState[] lineStates)
        {
            for (int i = 0; i < this.connections.Length; i++)
            {
                if (this.connections[i].ConnectionState == LobbyConnectionState.Connected)
                {
                    RCPackage lineStateReport = RCPackage.CreateNetworkControlPackage(Network.FORMAT_LOBBY_LINE_STATE_REPORT);
                    lineStateReport.WriteShort(0, (short)(i + 1));   /// The ID of the client that receives the report.
                    byte[] lineStatesBytes = new byte[lineStates.Length];
                    for (int j = 0; j < lineStatesBytes.Length; j++)
                    {
                        lineStatesBytes[j] = (byte)lineStates[j];
                    }
                    lineStateReport.WriteByteArray(1, lineStatesBytes);     /// The list of the line states on this server.

                    /// Send the package
                    if (!this.connections[i].SendPackage(lineStateReport))
                    {
                        /// In case of error, shutdown the connection and notify the other clients again.
                        this.connections[i].Shutdown();
                        this.connections[i].LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                        SendLineStateReports();
                    }
                }
            }
            this.listener.LineStateReport(0, lineStates);
        }
Пример #3
0
        /// <summary>
        /// Creates the package that contains the description of the isometric tiles of the given map.
        /// </summary>
        /// <param name="map">Reference to the map.</param>
        /// <returns>The data package that contains the description of the isometric tiles of the given map.</returns>
        private RCPackage CreateIsoTileListPackage(IMapAccess map)
        {
            RCPackage isotileList = RCPackage.CreateCustomDataPackage(MapFileFormat.ISOTILE_LIST);

            /// Create the terrain type index table.
            List <string> terrainTypeList = new List <string>();
            Dictionary <ITerrainType, int> terrainTypeIndexTable = new Dictionary <ITerrainType, int>();
            int terrainTypeIndex = 0;

            foreach (ITerrainType terrainType in map.Tileset.TerrainTypes)
            {
                terrainTypeList.Add(terrainType.Name);
                terrainTypeIndexTable.Add(terrainType, terrainTypeIndex);
                terrainTypeIndex++;
            }
            isotileList.WriteStringArray(0, terrainTypeList.ToArray());

            /// Create the packages of the isometric tiles.
            RCSet <IIsoTile> processedIsoTiles = new RCSet <IIsoTile>();
            List <RCPackage> isotilePackages   = new List <RCPackage>();
            int isotileInfoLength = 0;

            for (int row = 0; row < map.Size.Y; row++)
            {
                for (int column = 0; column < map.Size.X; column++)
                {
                    IIsoTile currIsoTile = map.GetQuadTile(new RCIntVector(column, row)).PrimaryIsoTile;
                    if (!processedIsoTiles.Contains(currIsoTile))
                    {
                        RCPackage isotilePackage = RCPackage.CreateCustomDataPackage(MapFileFormat.ISOTILE);
                        isotilePackage.WriteShort(0, (short)column);
                        isotilePackage.WriteShort(1, (short)row);
                        isotilePackage.WriteByte(2, (byte)terrainTypeIndexTable[currIsoTile.Type.TerrainA]);
                        isotilePackage.WriteByte(3, currIsoTile.Type.TerrainB != null ?
                                                 (byte)terrainTypeIndexTable[currIsoTile.Type.TerrainB] :
                                                 (byte)0);
                        isotilePackage.WriteByte(4, (byte)currIsoTile.Type.Combination);
                        isotilePackage.WriteByte(5, (byte)currIsoTile.VariantIdx);

                        isotilePackages.Add(isotilePackage);
                        processedIsoTiles.Add(currIsoTile);
                        isotileInfoLength += isotilePackage.PackageLength;
                    }
                }
            }

            /// Write the isometric tile packages into the final package
            byte[] isotileInfoBytes = new byte[isotileInfoLength];
            int    offset           = 0;

            foreach (RCPackage isotilePackage in isotilePackages)
            {
                offset += isotilePackage.WritePackageToBuffer(isotileInfoBytes, offset);
            }

            isotileList.WriteByteArray(1, isotileInfoBytes);
            return(isotileList);
        }
Пример #4
0
 /// <summary>
 /// Sends a DSS_LEAVE message to the other side of this session.
 /// </summary>
 /// <param name="reason">The reason of leaving the DSS.</param>
 /// <param name="customData">Custom data about leaving the DSS.</param>
 public void SendLeaveMsg(string reason, byte[] customData)
 {
     if (this.sm.CurrentState == this.SendingSetupStepRQ)
     {
         RCPackage leaveMsg = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_LEAVE);
         leaveMsg.WriteString(0, reason);
         leaveMsg.WriteByteArray(1, customData);
         this.manager.HostRoot.Lobby.SendControlPackage(leaveMsg, this.channel.Index + 1);
     }
 }
Пример #5
0
        /// <summary>
        /// Call this function to initialize the UI for the setup stage and send reset messages to the connected guests.
        /// </summary>
        private void FirstSetupStep(IDssGuestChannel[] channelsToGuests)
        {
            /// Reset the UI
            this.simulator.GetPlayer(0).Reset();
            this.simulator.GetPlayer(0).Activate();

            this.uiCallMarshal.SetMainControlStatus(FormStatus.HostSide);

            this.uiCallMarshal.SelectNewHostColor(this.simulator.GetPlayer(0).Color);
            this.uiCallMarshal.SetHostControlStatus(HostControlStatus.AccessGranted);

            this.previousChannelStates = new DssChannelState[channelsToGuests.Length];
            for (int i = 0; i < this.previousChannelStates.Length; i++)
            {
                this.simulator.GetPlayer(i + 1).Reset();
                this.previousChannelStates[i] = channelsToGuests[i].ChannelState;
                if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_OPENED)
                {
                    this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideOpened);
                }
                else if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_CLOSED)
                {
                    this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideClosed);
                }
                else if (channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED)
                {
                    this.simulator.GetPlayer(i + 1).Activate();
                    this.uiCallMarshal.SelectNewGuestColor(i, this.simulator.GetPlayer(i + 1).Color);
                    this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideEngaged);
                }
            }

            /// Send reset messages
            for (int i = 0; i < channelsToGuests.Length; i++)
            {
                if (channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED)
                {
                    byte[] colors  = new byte[this.simulator.MaxNumOfPlayers];
                    int[]  xCoords = new int[this.simulator.MaxNumOfPlayers];
                    int[]  yCoords = new int[this.simulator.MaxNumOfPlayers];
                    for (int j = 0; j < colors.Length; j++)
                    {
                        colors[j]  = (byte)this.simulator.GetPlayer(j).Color;
                        xCoords[j] = this.simulator.GetPlayer(j).Position.X;
                        yCoords[j] = this.simulator.GetPlayer(j).Position.Y;
                    }
                    RCPackage reset = RCPackage.CreateNetworkControlPackage(TestClientMessages.RESET);
                    reset.WriteByteArray(0, colors);
                    reset.WriteIntArray(1, xCoords);
                    reset.WriteIntArray(2, yCoords);
                    this.rqs[i].Add(reset);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Leaves the DSS.
        /// </summary>
        private void LeaveDss()
        {
            /// Send the DSS_LEAVE message to the host.
            RCPackage leavePackage = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_LEAVE);

            leavePackage.WriteString(0, "Guest left DSS!");
            leavePackage.WriteByteArray(1, new byte[0] {
            });
            this.guestRoot.Lobby.SendControlPackage(leavePackage);

            /// Stop the timeout clocks and exit from the event-loop.
            StopTimeouts();
            this.guestRoot.EventQueue.ExitEventLoop();
        }
Пример #7
0
        /// <summary>
        /// Sends a commit for this.nextNextRound to the lobby.
        /// </summary>
        /// <remarks>
        /// Call this function only if this.currentRound has been finished.
        /// </remarks>
        private void SendCommit()
        {
            if (!this.initialized)
            {
                throw new DssException("DssSimulationMgr is uninitialized!");
            }
            if (this.currentRound.StepNextFrame())
            {
                throw new DssException("DssSimulationMgr.SendCommit() denied!");
            }

            if (!this.hostLeft)
            {
                byte[] stateHash  = this.root.SimulatorIface.StateHash;
                int    highestAPT = this.HighestAPT;

                /// Generate a ticket for the commit.
                int ticket = -1;
                do
                {
                    ticket = RandomService.DefaultGenerator.Next();
                } while (this.commitAwMonitors.ContainsKey(ticket));

                /// Create the commit package.
                RCPackage commitPackage = RCPackage.CreateNetworkCustomPackage(DssRoot.DSS_COMMIT);
                commitPackage.WriteShort(0, (short)this.aftCalculator.Average);
                commitPackage.WriteShort(1, (short)highestAPT);           /// The highest measured APT
                commitPackage.WriteInt(2, this.nextNextRound.RoundIndex); /// Round index of the commit
                commitPackage.WriteInt(3, ticket);                        /// Commit answer ticket
                commitPackage.WriteByteArray(4, stateHash != null ? stateHash : new byte[0] {
                });                                                       /// State-hash value

                /// Send the commit package to the lobby.
                this.root.LobbyIface.SendPackage(commitPackage);

                RegisterCommitMonitor(ticket);

                TraceManager.WriteAllTrace(string.Format("Self commit round {0}", this.nextNextRound.RoundIndex), DssTraceFilters.SIMULATION_INFO);
                if (!this.nextNextRound.Commit(this.root.IdOfThisPeer, this.aftCalculator.Average, highestAPT, stateHash))
                {
                    SimulationStageError(string.Format("Commit of round-{0} failed!", this.nextNextRound.RoundIndex),
                                         new byte[0] {
                    });
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Creates the package that contains the description of the terrain objects of the given map.
        /// </summary>
        /// <param name="map">Reference to the map.</param>
        /// <returns>The data package that contains the description of the terrain objects of the given map.</returns>
        private RCPackage CreateTerrainObjListPackage(IMapAccess map)
        {
            RCPackage terrainObjList = RCPackage.CreateCustomDataPackage(MapFileFormat.TERRAINOBJ_LIST);

            /// Create the terrain object type index table.
            List <string> terrainObjTypeList = new List <string>();
            Dictionary <ITerrainObjectType, int> terrainObjTypeIndexTable = new Dictionary <ITerrainObjectType, int>();
            int terrainObjTypeIndex = 0;

            foreach (ITerrainObjectType terrainObjType in map.Tileset.TerrainObjectTypes)
            {
                terrainObjTypeList.Add(terrainObjType.Name);
                terrainObjTypeIndexTable.Add(terrainObjType, terrainObjTypeIndex);
                terrainObjTypeIndex++;
            }
            terrainObjList.WriteStringArray(0, terrainObjTypeList.ToArray());

            /// Create the packages of the terrain objects.
            List <RCPackage> terrainObjPackages = new List <RCPackage>();
            int terrainObjInfoLength            = 0;

            foreach (ITerrainObject terrainObj in map.TerrainObjects)
            {
                RCPackage terrainObjPackage = RCPackage.CreateCustomDataPackage(MapFileFormat.TERRAINOBJ);
                terrainObjPackage.WriteShort(0, (short)terrainObj.MapCoords.X);
                terrainObjPackage.WriteShort(1, (short)terrainObj.MapCoords.Y);
                terrainObjPackage.WriteByte(2, (byte)terrainObjTypeIndexTable[terrainObj.Type]);

                terrainObjPackages.Add(terrainObjPackage);
                terrainObjInfoLength += terrainObjPackage.PackageLength;
            }

            /// Write the terrain object packages into the final package
            byte[] terrainObjInfoBytes = new byte[terrainObjInfoLength];
            int    offset = 0;

            foreach (RCPackage terrainObjPackage in terrainObjPackages)
            {
                offset += terrainObjPackage.WritePackageToBuffer(terrainObjInfoBytes, offset);
            }

            terrainObjList.WriteByteArray(1, terrainObjInfoBytes);
            return(terrainObjList);
        }
Пример #9
0
        /// <summary>
        /// Sends a DSS_LEAVE message to the lobby and leaves the DSS.
        /// </summary>
        private void SendLeaveMessage()
        {
            if (!this.initialized)
            {
                throw new DssException("DssSimulationMgr is uninitialized!");
            }
            StopCommitTimeoutClock();
            StopSimulationFrameClock();
            UnregisterAllCommitMonitors();

            if (!this.hostLeft)
            {
                RCPackage leaveMessage = RCPackage.CreateNetworkCustomPackage(DssRoot.DSS_LEAVE);
                leaveMessage.WriteString(0, "Leave DSS during simulation stage!");
                leaveMessage.WriteByteArray(1, new byte[0] {
                });
                this.root.LobbyIface.SendPackage(leaveMessage);
            }
        }
Пример #10
0
        /// <summary>
        /// Internal function to send a DSS_CTRL_DROP_GUEST message to the other side of this session.
        /// </summary>
        public void DropGuest()
        {
            if (this.sm.CurrentState == this.SendingSetupStepRQ)
            {
                RCPackage dropGuestMsg = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_CTRL_DROP_GUEST);
                dropGuestMsg.WriteString(0, "Dropped from the DSS by the host.");
                dropGuestMsg.WriteByteArray(1, new byte[0] {
                });

                /// Send the DSS_CTRL_DROP_GUEST message to the guest and close the line immediately
                this.manager.HostRoot.Lobby.SendControlPackage(dropGuestMsg, this.channel.Index + 1);
                this.manager.HostRoot.Lobby.CloseLine(this.channel.Index + 1);

                /// Move the session back to inactive state.
                this.SendingSetupStepRQ_Inactive.Fire();
            }
            else
            {
                throw new DssException("Illegal call to DssHostSessionSM.DropGuest");
            }
        }
Пример #11
0
        /// <summary>
        /// Internal function to timestamp and send the given commands to the lobby.
        /// </summary>
        /// <param name="cmds">The list of the commands to send.</param>
        private void SendCommandsToLobby(RCPackage[] cmds)
        {
            if (!this.initialized)
            {
                throw new DssException("DssSimulationMgr is uninitialized!");
            }
            if (cmds != null && cmds.Length != 0)
            {
                /// Compute the length of the buffer needed for sending the commands as a byte sequence
                int bufferLength = 0;
                for (int i = 0; i < cmds.Length; i++)
                {
                    if (cmds[i] != null && cmds[i].IsCommitted && cmds[i].PackageType == RCPackageType.CUSTOM_DATA_PACKAGE &&
                        !DssRoot.IsInternalFormat(cmds[i].PackageFormat))
                    {
                        bufferLength += cmds[i].PackageLength;
                    }
                    else
                    {
                        throw new DssException("Unexpected command from the client module!");
                    }
                }

                /// Create the buffer and write the commands into this buffer
                byte[] cmdBuffer = new byte[bufferLength];
                int    offset    = 0;
                for (int i = 0; i < cmds.Length; i++)
                {
                    offset += cmds[i].WritePackageToBuffer(cmdBuffer, offset);
                }

                /// Create the DSS_COMMAND package and send it to the lobby
                RCPackage cmdPackage = RCPackage.CreateNetworkCustomPackage(DssRoot.DSS_COMMAND);
                cmdPackage.WriteInt(0, this.nextNextRound.RoundIndex);       /// Round index of the command
                cmdPackage.WriteInt(1, this.currentRound.CurrentFrameIndex); /// Frame index of the command
                cmdPackage.WriteByteArray(2, cmdBuffer);                     /// The command list

                this.root.LobbyIface.SendPackage(cmdPackage);                /// Send the command package to the lobby
            }
        }
Пример #12
0
 /// <summary>
 /// Starts the disconnection procedure of this connection.
 /// </summary>
 /// <returns>True if the disconnection procedure has been successfully started, false otherwise.</returns>
 /// <remarks>
 /// If this function returns false that means that an underlying network error occured and the connection
 /// has been shutdown immediately.
 /// </remarks>
 public bool BeginDisconnect()
 {
     if (this.connectionState == LobbyConnectionState.Connected)
     {
         /// Send a disconnect indicator message to the other side.
         RCPackage disconnectIndicator = RCPackage.CreateNetworkControlPackage(Network.FORMAT_DISCONNECT_INDICATOR);
         disconnectIndicator.WriteString(0, string.Empty);
         disconnectIndicator.WriteByteArray(1, new byte[0] {
         });
         if (!SendPackage(disconnectIndicator))
         {
             /// Shutdown the connection immediately in case of any error.
             Shutdown();
             return(false);
         }
         this.connectionState = LobbyConnectionState.Disconnecting;
         this.disconnectAckMsgTimer.Start();
         return(true);
     }
     else
     {
         throw new NetworkingSystemException("Unexpected call to LobbyConnection.BeginDisconnect()!");
     }
 }
Пример #13
0
 /// <summary>
 /// Process all incoming messages arrived from all connections.
 /// </summary>
 private void ProcessIncomingMessages()
 {
     for (int i = 0; i < this.connections.Length; i++)
     {
         if (this.connections[i].ConnectionState == LobbyConnectionState.Connected)
         {
             /// The connection is in connected state --> it's incoming messages will be processed by the server
             List <RCPackage> incomingPackages = new List <RCPackage>();
             if (this.connections[i].ReceiveIncomingPackages(ref incomingPackages))
             {
                 /// Process the incoming messages
                 foreach (RCPackage package in incomingPackages)
                 {
                     if (package.PackageType == RCPackageType.NETWORK_CUSTOM_PACKAGE)
                     {
                         /// This is a custom message, forward it to every other clients
                         package.Sender = i + 1;
                         for (int j = 0; j < this.connections.Length; j++)
                         {
                             if (i != j && this.connections[j].ConnectionState == LobbyConnectionState.Connected)
                             {
                                 if (!this.connections[j].SendPackage(package))
                                 {
                                     /// Unable to forward the message to a client --> Shutdown the connection
                                     this.connections[j].Shutdown();
                                     this.connections[j].LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                                     SendLineStateReports();
                                 }
                             }
                         }
                         /// Notify the listener object about the arrived package
                         this.listener.PackageArrived(package, i + 1);
                     }
                     else if (package.PackageType == RCPackageType.NETWORK_CONTROL_PACKAGE &&
                              package.PackageFormat.ID == Network.FORMAT_DEDICATED_MESSAGE)
                     {
                         /// This is a dedicated message, forward only to the targets
                         byte[]    targets         = package.ReadByteArray(0); /// List of the targets
                         byte[]    theMessageBytes = package.ReadByteArray(1); /// The embedded message
                         int       parsedBytes     = 0;
                         RCPackage theMessage      = RCPackage.Parse(theMessageBytes, 0, theMessageBytes.Length, out parsedBytes);
                         if (theMessage != null && theMessage.IsCommitted && theMessage.PackageType == RCPackageType.NETWORK_CUSTOM_PACKAGE)
                         {
                             /// The embedded message is OK --> forward it to the dedicated targets
                             theMessage.Sender = i + 1;
                             for (int j = 0; j < targets.Length; j++)
                             {
                                 int target = targets[j];
                                 if (target == 0)
                                 {
                                     /// This server is the target
                                     this.listener.PackageArrived(theMessage, i + 1);
                                 }
                                 else if (target - 1 >= 0 && target - 1 < this.connections.Length && target - 1 != i)
                                 {
                                     /// Another client is the target --> forward the message to it
                                     LobbyConnection targetConn = this.connections[target - 1];
                                     if (targetConn.ConnectionState == LobbyConnectionState.Connected)
                                     {
                                         if (!targetConn.SendPackage(theMessage))
                                         {
                                             /// Unable to forward the message to a target --> Shutdown the connection
                                             targetConn.Shutdown();
                                             targetConn.LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                                             SendLineStateReports();
                                         }
                                     }
                                 }
                             }
                         }
                         else
                         {
                             /// The embedded message has unexpected format --> Shutdown the connection
                             this.connections[i].Shutdown();
                             this.connections[i].LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                             SendLineStateReports();
                             break;                                                 /// Stop processing the messages of the closed connection
                         }
                     }
                     else if (this.connections[i].ConnectionState == LobbyConnectionState.Connected &&
                              package.PackageType == RCPackageType.NETWORK_CONTROL_PACKAGE &&
                              package.PackageFormat.ID == Network.FORMAT_DISCONNECT_INDICATOR)
                     {
                         /// The client at the other side of the connection wants to disconnect.
                         /// Acknowledge this request and shutdown the connection.
                         RCPackage disconnAck = RCPackage.CreateNetworkControlPackage(Network.FORMAT_DISCONNECT_ACK);
                         disconnAck.WriteString(0, string.Empty);
                         disconnAck.WriteByteArray(1, new byte[0] {
                         });
                         this.connections[i].SendPackage(disconnAck);
                         this.connections[i].Shutdown();
                         this.connections[i].LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                         SendLineStateReports();
                         break;                                                 /// Stop processing the messages of the closed connection
                     }
                     else if (package.PackageType == RCPackageType.NETWORK_CONTROL_PACKAGE &&
                              package.PackageFormat.ID != Network.FORMAT_DEDICATED_MESSAGE &&
                              package.PackageFormat.ID != Network.FORMAT_DISCONNECT_ACK &&
                              package.PackageFormat.ID != Network.FORMAT_DISCONNECT_INDICATOR &&
                              package.PackageFormat.ID != Network.FORMAT_LOBBY_INFO &&
                              package.PackageFormat.ID != Network.FORMAT_LOBBY_INFO_VANISHED &&
                              package.PackageFormat.ID != Network.FORMAT_LOBBY_LINE_STATE_REPORT)
                     {
                         /// Custom internal message from a client --> notify the listener
                         this.listener.ControlPackageArrived(package, i + 1);
                     }
                     else
                     {
                         /// Unexpected message from the current connection
                         this.connections[i].Shutdown();
                         this.connections[i].LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                         SendLineStateReports();
                         break;                                                 /// Stop processing the messages of the closed connection
                     }
                 } /// end-foreach (RCPackage package in incomingPackages)
             }
             else
             {
                 /// In case of receive error, we shutdown the connection.
                 this.connections[i].Shutdown();
                 this.connections[i].LineState = LobbyLineState.Opened; /// Keep it opened for other clients.
                 SendLineStateReports();
             }
         }
         else if (this.connections[i].ConnectionState == LobbyConnectionState.Disconnecting)
         {
             /// The connection is about to disconnect --> incoming messages will be handled by the connection itself
             if (this.connections[i].ContinueDisconnect())
             {
                 /// This connection remains closed because disconnection is initiated by the server.
                 SendLineStateReports();
             }
         }
     } /// end-for (int i = 0; i < this.connections.Length; i++)
 }
Пример #14
0
        /// <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;
            }
        }
Пример #15
0
        /// <summary>
        /// Resets the state of the DssSimulationMgr. Call this function every time you start a simulation stage.
        /// </summary>
        /// <param name="opFlags">
        /// The current operator flag array. See the comment at this.operatorFlags for more information.
        /// </param>
        public void Reset(bool[] opFlags)
        {
            if (opFlags == null)
            {
                throw new ArgumentNullException("opFlags");
            }
            if (opFlags.Length != this.root.OpCount)
            {
                throw new ArgumentException("Array length mismatch.", "opFlags");
            }

            this.aftCalculator = new AverageCalculator(DssConstants.AVG_CALC_VECTOR_LENGTH,
                                                       DssConstants.INITIAL_AFT);
            this.aptCalculators = new AverageCalculator[this.root.OpCount];
            for (int i = 0; i < this.aptCalculators.Length; i++)
            {
                this.aptCalculators[i] = new AverageCalculator(DssConstants.AVG_CALC_VECTOR_LENGTH,
                                                               DssConstants.INITIAL_APT);
            }

            if (this.commitAwTimeouts != null)
            {
                foreach (KeyValuePair <AlarmClock, CommitMonitor> item in this.commitAwTimeouts)
                {
                    item.Key.Cancel();
                }
            }
            this.commitAwMonitors = new Dictionary <int, CommitMonitor>();
            this.commitAwTimeouts = new Dictionary <AlarmClock, CommitMonitor>();

            StopCommitTimeoutClock();
            StopSimulationFrameClock();

            this.operatorFlags = opFlags;

            this.currentRound = new SimulationRound(this.operatorFlags);
            this.currentRound.Reset(true, 0);
            this.currentRound.ComputeSpeedControl();
            this.nextRound = new SimulationRound(this.operatorFlags);
            this.nextRound.Reset(false, 1);
            this.nextNextRound = new SimulationRound(this.operatorFlags);
            this.nextNextRound.Reset(false, 2);
            this.nextNextNextRound = new SimulationRound(this.operatorFlags);
            this.nextNextNextRound.Reset(false, 3);
            this.waitingForCommit = false;

            this.initialized = true;
            this.hostLeft    = false;

            int ticket = RandomService.DefaultGenerator.Next();

            byte[] stateHash  = this.root.SimulatorIface.StateHash;
            int    highestAPT = this.HighestAPT;

            this.commitTimeoutClock = this.root.AlarmClkMgr.SetAlarmClock(DssRoot.Time + DssConstants.COMMIT_TIMEOUT,
                                                                          this.CommitTimeout);

            /// Create the first commit package.
            RCPackage commitPackage = RCPackage.CreateNetworkCustomPackage(DssRoot.DSS_COMMIT);

            commitPackage.WriteShort(0, (short)this.aftCalculator.Average);
            commitPackage.WriteShort(1, (short)highestAPT); /// The highest measured APT
            commitPackage.WriteInt(2, 1);                   /// Round index of the commit is 1 (next round is committed)
            commitPackage.WriteInt(3, ticket);              /// Commit answer ticket
            commitPackage.WriteByteArray(4, stateHash != null ? stateHash : new byte[0] {
            });                                             /// State-hash value

            /// Send the commit package to the lobby.
            this.root.LobbyIface.SendPackage(commitPackage);

            RegisterCommitMonitor(ticket);

            TraceManager.WriteAllTrace(string.Format("Self commit round {0}", this.nextRound.RoundIndex), DssTraceFilters.SIMULATION_INFO);
            if (!this.nextRound.Commit(this.root.IdOfThisPeer, this.aftCalculator.Average, highestAPT, stateHash))
            {
                SimulationStageError(string.Format("Commit of round-{0} failed!", this.nextRound.RoundIndex),
                                     new byte[0] {
                });
            }
        }
Пример #16
0
        /// <summary>
        /// The function sends every outgoing messages.
        /// </summary>
        /// <returns>False if the connection manager thread has to stop, true otherwise.</returns>
        private bool SendOutgoingMessages()
        {
            bool errorOccured = false;

            lock (this.outgoingPackages)
            {
                if (this.outgoingPackages.Count == this.outgoingPackageTargets.Count)
                {
                    if (this.connection.ConnectionState == LobbyConnectionState.Connected)
                    {
                        for (int i = 0; i < this.outgoingPackages.Count; i++)
                        {
                            int[] targets = this.outgoingPackageTargets[i];
                            if (targets != null)
                            {
                                /// This is a dedicated message --> Send it as an embedded message.
                                /// First collect the targets.
                                List <byte> targetBytesList = new List <byte>();
                                for (int j = 0; j < targets.Length; j++)
                                {
                                    if (targets[j] != this.clientID && targets[j] >= 0 && targets[j] < this.memberCount)
                                    {
                                        targetBytesList.Add((byte)targets[j]);
                                    }
                                }
                                /// Then create the dedicated message and send it to the server.
                                byte[] targetBytes = targetBytesList.ToArray();
                                if (targetBytes != null && targetBytes.Length > 0)
                                {
                                    byte[] packageBytes = new byte[this.outgoingPackages[i].PackageLength];
                                    this.outgoingPackages[i].WritePackageToBuffer(packageBytes, 0);
                                    RCPackage dedicatedPackage = RCPackage.CreateNetworkControlPackage(Network.FORMAT_DEDICATED_MESSAGE);
                                    dedicatedPackage.WriteByteArray(0, targetBytes);    /// The targets of the message.
                                    dedicatedPackage.WriteByteArray(1, packageBytes);   /// The message itself.
                                    if (!this.connection.SendPackage(dedicatedPackage))
                                    {
                                        /// Error when try to send --> immediate shutdown.
                                        this.connection.Shutdown();
                                        //if (this.Disposed != null) { this.Disposed(this); }
                                        //this.listener.LobbyLost();
                                        errorOccured = true;
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                /// This is a simple message.
                                if (!this.connection.SendPackage(this.outgoingPackages[i]))
                                {
                                    /// Error when try to send --> immediate shutdown.
                                    this.connection.Shutdown();
                                    //if (this.Disposed != null) { this.Disposed(this); }
                                    //this.listener.LobbyLost();
                                    errorOccured = true;
                                    break;
                                }
                            }
                        }
                    }

                    /// Clear the FIFO
                    this.outgoingPackages.Clear();
                    this.outgoingPackageTargets.Clear();

                    /// Outgoing messages sent successfully.
                    ///return true;
                }
                else
                {
                    throw new NetworkingSystemException("Inconsistence in the outgoing package FIFO!");
                }
            }

            if (errorOccured)
            {
                /// An error happened during the send.
                if (this.Disposed != null)
                {
                    this.Disposed(this);
                }
                this.listener.LobbyLost();
                return(false);
            }
            else
            {
                /// Outgoing messages sent successfully.
                return(true);
            }
        }
Пример #17
0
        /// <summary>
        /// This function reads and processes every incoming message arriving from the server.
        /// </summary>
        /// <returns>False, if the connection manager thread has to stop, true otherwise.</returns>
        private bool ProcessIncomingMessages()
        {
            List <RCPackage> incomingPackages = new List <RCPackage>();

            if (this.connection.ReceiveIncomingPackages(ref incomingPackages))
            {
                foreach (RCPackage package in incomingPackages)
                {
                    if (package.PackageType == RCPackageType.NETWORK_CUSTOM_PACKAGE &&
                        package.Sender >= 0 && package.Sender < this.memberCount && package.Sender != this.clientID)
                    {
                        /// Custom message from a member --> notify the listener.
                        this.listener.PackageArrived(package, package.Sender);
                    }
                    else if (package.PackageType == RCPackageType.NETWORK_CONTROL_PACKAGE &&
                             package.PackageFormat.ID == Network.FORMAT_LOBBY_LINE_STATE_REPORT)
                    {
                        /// Line state report from the server.
                        short            clientID       = package.ReadShort(0);
                        byte[]           lineStateBytes = package.ReadByteArray(1);
                        LobbyLineState[] lineStates     = new LobbyLineState[lineStateBytes.Length];
                        bool             lineStatesOK   = true;
                        for (int i = 0; i < lineStateBytes.Length; i++)
                        {
                            if (lineStateBytes[i] == (byte)LobbyLineState.Closed ||
                                lineStateBytes[i] == (byte)LobbyLineState.Engaged ||
                                lineStateBytes[i] == (byte)LobbyLineState.Opened)
                            {
                                lineStates[i] = (LobbyLineState)lineStateBytes[i];
                            }
                            else
                            {
                                lineStatesOK = false;
                            }
                        }
                        lineStatesOK = lineStatesOK && (clientID == this.clientID) && (lineStateBytes.Length == this.memberCount);
                        if (!lineStatesOK)
                        {
                            /// Line state report error --> shutdown.
                            this.connection.Shutdown();
                            if (this.Disposed != null)
                            {
                                this.Disposed(this);
                            }
                            this.listener.LobbyLost();
                            return(false);
                        }
                        else
                        {
                            /// Line state report arrived --> notify the listener
                            this.listener.LineStateReport(clientID, lineStates);
                            ///return true;
                        }
                    }
                    else if (package.PackageType == RCPackageType.NETWORK_CONTROL_PACKAGE &&
                             package.PackageFormat.ID == Network.FORMAT_DISCONNECT_INDICATOR)
                    {
                        /// Disconnection indicator from the server.
                        RCPackage disconnectAck = RCPackage.CreateNetworkControlPackage(Network.FORMAT_DISCONNECT_ACK);
                        disconnectAck.WriteString(0, string.Empty);
                        disconnectAck.WriteByteArray(1, new byte[0] {
                        });
                        this.connection.SendPackage(disconnectAck);
                        this.connection.Shutdown();
                        if (this.Disposed != null)
                        {
                            this.Disposed(this);
                        }
                        this.listener.LobbyLost();
                        return(false);
                    }
                    else if (package.PackageType == RCPackageType.NETWORK_CONTROL_PACKAGE &&
                             package.PackageFormat.ID != Network.FORMAT_DEDICATED_MESSAGE &&
                             package.PackageFormat.ID != Network.FORMAT_DISCONNECT_ACK &&
                             package.PackageFormat.ID != Network.FORMAT_DISCONNECT_INDICATOR &&
                             package.PackageFormat.ID != Network.FORMAT_LOBBY_INFO &&
                             package.PackageFormat.ID != Network.FORMAT_LOBBY_INFO_VANISHED &&
                             package.PackageFormat.ID != Network.FORMAT_LOBBY_LINE_STATE_REPORT)
                    {
                        /// Custom internal message from the server --> notify the listener
                        TraceManager.WriteAllTrace(string.Format("Incoming package: {0}", package.ToString()), NetworkingSystemTraceFilters.INFO);
                        this.listener.ControlPackageArrived(package);
                    }
                    else
                    {
                        /// Unexpected package format and type --> immediate shutdown
                        this.connection.Shutdown();
                        if (this.Disposed != null)
                        {
                            this.Disposed(this);
                        }
                        this.listener.LobbyLost();
                        return(false);
                    }
                } /// end-foreach (RCPackage package in incomingPackages)

                /// Incoming packages has been processed.
                return(true);
            }
            else
            {
                /// Receive error --> immediate shutdown
                this.connection.Shutdown();
                if (this.Disposed != null)
                {
                    this.Disposed(this);
                }
                this.listener.LobbyLost();
                return(false);
            }
        }
Пример #18
0
        public static RCPackage GenerateRandomPackage()
        {
            int       rndType   = rnd.Next(0, 3);
            int       rndFormat = rnd.Next(0, 3);
            RCPackage retPack   = null;

            if (rndType == 0)
            {
                retPack = RCPackage.CreateNetworkPingPackage(); return(retPack);
            }
            else if (rndType == 1)
            {
                retPack = RCPackage.CreateCustomDataPackage(rndFormat);
            }
            else if (rndType == 2)
            {
                retPack = RCPackage.CreateNetworkCustomPackage(rndFormat);
            }

            RCPackageFormat format = RCPackageFormat.GetPackageFormat(rndFormat);

            for (int i = 0; i < format.NumOfFields; i++)
            {
                RCPackageFieldType datatype = format.GetFieldType(i);
                if (datatype == RCPackageFieldType.BYTE)
                {
                    retPack.WriteByte(i, (byte)rnd.Next(byte.MinValue, byte.MaxValue));
                }
                else if (datatype == RCPackageFieldType.SHORT)
                {
                    retPack.WriteShort(i, (short)rnd.Next(short.MinValue, short.MaxValue));
                }
                else if (datatype == RCPackageFieldType.INT)
                {
                    retPack.WriteInt(i, (int)rnd.Next(int.MinValue, int.MaxValue));
                }
                else if (datatype == RCPackageFieldType.LONG)
                {
                    retPack.WriteLong(i, (long)rnd.Next(int.MinValue, int.MaxValue));
                }
                else if (datatype == RCPackageFieldType.STRING)
                {
                    int strIdx = rnd.Next(0, 10);
                    retPack.WriteString(i, strCollection[strIdx]);
                }
                else if (datatype == RCPackageFieldType.BYTE_ARRAY)
                {
                    int    arrLen = rnd.Next(0, 10);
                    byte[] arr    = new byte[arrLen];
                    rnd.NextBytes(arr);
                    retPack.WriteByteArray(i, arr);
                }
                else if (datatype == RCPackageFieldType.SHORT_ARRAY)
                {
                    int     arrLen = rnd.Next(0, 10);
                    short[] arr    = new short[arrLen];
                    for (int j = 0; j < arrLen; ++j)
                    {
                        arr[j] = (short)rnd.Next(short.MinValue, short.MaxValue);
                    }
                    retPack.WriteShortArray(i, arr);
                }
                else if (datatype == RCPackageFieldType.INT_ARRAY)
                {
                    int   arrLen = rnd.Next(0, 10);
                    int[] arr    = new int[arrLen];
                    for (int j = 0; j < arrLen; ++j)
                    {
                        arr[j] = (int)rnd.Next(int.MinValue, int.MaxValue);
                    }
                    retPack.WriteIntArray(i, arr);
                }
                else if (datatype == RCPackageFieldType.LONG_ARRAY)
                {
                    int    arrLen = rnd.Next(0, 10);
                    long[] arr    = new long[arrLen];
                    for (int j = 0; j < arrLen; ++j)
                    {
                        arr[j] = (long)rnd.Next(int.MinValue, int.MaxValue);
                    }
                    retPack.WriteLongArray(i, arr);
                }
                else if (datatype == RCPackageFieldType.STRING_ARRAY)
                {
                    int      arrLen = rnd.Next(0, 10);
                    string[] arr    = new string[arrLen];
                    for (int j = 0; j < arrLen; ++j)
                    {
                        int strIdx = rnd.Next(0, 10);
                        arr[j] = strCollection[strIdx];
                    }
                    retPack.WriteStringArray(i, arr);
                }
                else
                {
                    throw new NetworkingSystemException("Unknown datatype");
                }
            }

            return(retPack);
        }
Пример #19
0
        /// <summary>
        /// Processes the channel events and incoming answers arrived from the guests.
        /// </summary>
        private void ProcessGuestChannels(IDssGuestChannel[] channelsToGuests)
        {
            RCSet <int> newGuests = new RCSet <int>();

            /// First collect the new guests
            for (int i = 0; i < this.previousChannelStates.Length; i++)
            {
                if (this.previousChannelStates[i] != channelsToGuests[i].ChannelState)
                {
                    /// The state of a channel has changed
                    this.previousChannelStates[i] = channelsToGuests[i].ChannelState;
                    if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_OPENED)
                    {
                        this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideOpened);
                    }
                    else if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_CLOSED)
                    {
                        this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideClosed);
                    }
                    else if (channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED)
                    {
                        this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideEngaged);
                        this.simulator.GetPlayer(i + 1).Activate();
                        newGuests.Add(i);
                    }
                }
            }

            /// Then process the answers of any other guests.
            for (int i = 0; i < this.previousChannelStates.Length; i++)
            {
                if (!newGuests.Contains(i) && channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED)
                {
                    /// If a guest is connected to this channel, process it's answer.
                    RCPackage[] answerFromGuest = channelsToGuests[i].AnswerFromGuest;
                    for (int j = 0; j < answerFromGuest.Length; j++)
                    {
                        if (answerFromGuest[j].PackageFormat.ID == TestClientMessages.COLOR_CHANGE_REQUEST)
                        {
                            /// Color change request arrived from the guest.
                            PlayerColor newColor = (PlayerColor)answerFromGuest[j].ReadByte(0);
                            this.simulator.GetPlayer(i + 1).Color = newColor;

                            /// Notify the other connected guests.
                            for (int k = 0; k < channelsToGuests.Length; k++)
                            {
                                if (!newGuests.Contains(k) && i != k && channelsToGuests[k].ChannelState == DssChannelState.GUEST_CONNECTED)
                                {
                                    RCPackage colorChgNotif =
                                        RCPackage.CreateNetworkControlPackage(TestClientMessages.COLOR_CHANGE_NOTIFICATION);
                                    colorChgNotif.WriteInt(0, i + 1);
                                    colorChgNotif.WriteByte(1, (byte)newColor);
                                    this.rqs[k].Add(colorChgNotif);
                                }
                            }

                            /// Notify the UI
                            this.uiCallMarshal.SelectNewGuestColor(i, newColor);
                            break;  /// Ignore the remaining messages
                        }
                    }
                }
            }

            /// Send a reset message to the new guests
            foreach (int newGuestIdx in newGuests)
            {
                byte[] colors  = new byte[this.simulator.MaxNumOfPlayers];
                int[]  xCoords = new int[this.simulator.MaxNumOfPlayers];
                int[]  yCoords = new int[this.simulator.MaxNumOfPlayers];
                for (int j = 0; j < colors.Length; j++)
                {
                    colors[j]  = (byte)this.simulator.GetPlayer(j).Color;
                    xCoords[j] = this.simulator.GetPlayer(j).Position.X;
                    yCoords[j] = this.simulator.GetPlayer(j).Position.Y;
                }
                RCPackage reset = RCPackage.CreateNetworkControlPackage(TestClientMessages.RESET);
                reset.WriteByteArray(0, colors);
                reset.WriteIntArray(1, xCoords);
                reset.WriteIntArray(2, yCoords);
                this.rqs[newGuestIdx].Add(reset);
            }
        }
Пример #20
0
        /// <summary>
        /// Starts the simulation.
        /// </summary>
        private void StartSimulation()
        {
            /// Collect opFlags and channel state informations.
            byte[] chStates = new byte[this.channelProxies.Length];
            bool[] opFlags  = new bool[this.hostRoot.OpCount];
            opFlags[0] = true;

            for (int i = 0; i < chStates.Length; i++)
            {
                if (this.channels[i].CurrentState == this.channels[i].Opened)
                {
                    /// If the channel is opened then it will be closed.
                    //this.channels[i].CloseChannel();
                    this.channels[i].PermanentlyClose();
                    chStates[i]    = (byte)DssChannelState.CHANNEL_CLOSED;//CHANNEL_OPENED;
                    opFlags[i + 1] = false;
                }
                else if (this.channels[i].CurrentState == this.channels[i].Closed)
                {
                    /// If the channel is closed then it will remain closed.
                    this.channels[i].PermanentlyClose();
                    chStates[i]    = (byte)DssChannelState.CHANNEL_CLOSED;
                    opFlags[i + 1] = false;
                }
                else if (this.channels[i].CurrentState == this.channels[i].Engaged)
                {
                    /// If the channel is engaged then we have to check whether the guest will be dropped or not.
                    if (this.channelProxies[i].TaskToPerform == DssChannelTask.DROP_AND_OPEN ||
                        this.channelProxies[i].TaskToPerform == DssChannelTask.DROP_AND_CLOSE)
                    {
                        /// Close channel permanently.
                        this.channels[i].PermanentlyClose();
                        this.hostRoot.GuestLeftDss(i);
                        chStates[i]    = (byte)DssChannelState.CHANNEL_CLOSED;
                        opFlags[i + 1] = false;
                    }
                    else
                    {
                        /// Don't drop guest, it will participate in the simulation stage.
                        chStates[i]    = (byte)DssChannelState.GUEST_CONNECTED;
                        opFlags[i + 1] = true;
                    }
                }
                else
                {
                    throw new DssException("Unexpected channel state!");
                }
            }
            int[] leftList = null;
            int[] lostList = null;
            this.hostRoot.GetGuestEvents(out leftList, out lostList);

            RCPackage startSimMsg = RCPackage.CreateNetworkControlPackage(DssRoot.DSS_CTRL_START_SIMULATION);

            startSimMsg.WriteIntArray(0, leftList);
            startSimMsg.WriteIntArray(1, lostList);
            startSimMsg.WriteByteArray(2, chStates);

            /// Send the DSS_CTRL_START_SIMULATION message to every engaged channels
            for (int i = 0; i < this.sessions.Length; i++)
            {
                if (opFlags[i + 1])
                {
                    /// Push the corresponding session and channel to the Simulating state
                    this.channels[i].StartSimulation();
                    this.sessions[i].StartSimulation();

                    /// Send the start message to the corresponding guest
                    this.hostRoot.Lobby.SendControlPackage(startSimMsg, i + 1);
                }
            }

            /// Reset the simulation manager and ask it to execute the next frame immediately.
            this.hostRoot.SimulationMgr.Reset(opFlags);
            this.hostRoot.SimulationMgr.SetNextFrameExecutionTime(DssRoot.Time);

            /// And finally go to the SimulationStage.
            this.SendingSetupStepRQs_SimulationStage.Fire();
        }